Cant access key values from an Object in Reactjs after fetching - json

I have a user details page in Reactjs where I'm fetching the user details and populating it to the corresponding fields. But I'm not able to access key values from the user object.
My sample code is
function EditProfile(props) {
const [user, setUser] = useState()
useEffect(() => {
const fetchUserInfo = async () => {
const profileConfig = {
method: 'GET',
headers: {
'Authorization': 'Bearer ' + auth.token
}
};
fetch(`http://localhost:4000/api/v1/user/me`, profileConfig)
.then(response => response.json())
.then(response => {
console.log("response: ", response.user);
if (response.success === true) {
setUser(response.user)
} else {
alert(response.message)
}
},
(error) => {
alert('User fetching faied: ' + error)
})
}
fetchUserInfo()
}, [])
return (
<div>{user.name}</div>
)
}
The response from the server (user object is)
{
"status": true,
"_id": "5ecfdc403165f709b49a4a0e",
"name": "Anand OL",
"gender": "male",
"dob": "2020-12-13T00:00:00.000Z",
"email": "anand#gmail.com",
"phone": "1234567890",
"createdAt": "2020-05-28T15:44:00.700Z",
"updatedAt": "2020-06-01T08:38:37.902Z",
"__v": 136,
"image": "5ecfdc403165f709b49a4a0e_Image.png"
}
when I try to access name from the user object like user.name
I'm getting an error user is not defined

You need to provide some initial state to display (or conditionally render) while the fetch is occuring.
const [user, setUser] = useState(); // <-- user is undefined!!
Conditionally render UI
return <div>{user && user.name}</div>;
or
return user ? <div>{user.name}</div> : null;
Note: Use caution with the former as not all falsey values are created equal, i.e. Consider return <div>{value && value.property}</div>, if/when value = 0 a falsey value, then a "0" will actually be rendered.
Or you can provide some default state
const [user, setUser] = useState({ name: '' });

Related

Function passing null at first run

i have a little problem with passing data into a JSON file. I have a function that runs onClick. The first run returned:
{
"title": "",
"description": "",
"price": "",
"id": 1
}
but all next runs returns data correctly:
{
"title": "Example title",
"description": "Example description",
"price": "$7",
"id": 2
}
Anyone know how to fix it?
My react code:
const [title, setTitle] = useState('');
const [description, setDescription] = useState('');
const [price, setPrice] = useState('');
const addToCart = (e) => {
e.preventDefault();
setTitle('Example title');
setDescription('Example description');
setPrice('$' + Math.floor(Math.random() * 10 + 1));
const product = { title, description, price};
fetch('http://localhost:8000/basket', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(product)
})
.catch((err) => {
console.log(err.message);
})
}
Because setState is async and only update when component re-render. So you can declare variable to use in post and in setState.
const addToCart = (e) => {
e.preventDefault();
const product = {
title: "Example title",
description: "Example description",
price: "$" + Math.floor(Math.random() * 10 + 1),
};
setTitle(product.title);
setDescription(product.description);
setPrice(product.price);
fetch("http://localhost:8000/basket", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(product),
}).catch((err) => {
console.log(err.message);
});
};
It's likely breaking because you're trying to set state while making a fetch call, on initial empty state values. The design here is wrong, you shouldn't be assigning hard coded state while making a fetch call.
const Form = () => {
const [value, setValue] = useState('')
const submit = () => {
// make fetch call here using value
}
return <form onSubmit={(e) => {e.preventDefault(); submit()}}>
<input type='text' value={value} onChange={(e) => setValue(e.target.value)}
</form>
}

React JSON is undefined

I'm fetching this JSON from an API:
{
"data": {
"email": "test#tre.com",
"inserted_at": "2021-03-30T15:37:06",
"links": [
{
"id": 1,
"title": "My link title",
"url": "http://google.com"
},
{
"id": 2,
"title": "My Youube title",
"url": "http://youtube.com"
}
]
}
}
I'm fetching it this way using Hooks:
export default function Notes() {
const [json, setJSON] = useState([]);
useEffect(() => {
fetch("http://localhost:4000/api/users/1", {
method: "GET"
})
.then((response) => response.json())
.then((json) => {
// console.log(data);
setJSON(json);
})
.catch((err) => {
console.error(err);
});
}, [setJSON]);
Then I try to show it like this:
return (
<>
<div className="content">
{JSON.stringify(json)}
<h1>{json.email}</h1>
</div>
</>
);
The line {JSON.stringify(json)} shows the JSON.
But the line <h1>{json.email}</h1> doesn't show anything.
I don't know why that happens and how can I access my variables.
Thanks . I appreciate any help
Is the data in the form of an array or an object?
You defined the initial state as and array ad hence you cannot do
// you can't do json.email if you expect the response as and array
const [json, setJSON] = useState([]);
change it to
const [json, setJSON] = useState({});
if it is an object. Then in the template do
{json.data && <h1>{json.data.email}</h1>}
<h1>{json.data && json.data.email}</h1>
instead of
<h1>{json.email}</h1>

directline connection role and name not getting in BOT conversationUpdate

//For reference below - DirectLine Connection code
```(async function() {
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({
secret: “My KEY”}),
userID : "myid",
username: "myName"
},
document.getElementById('chat_converse')
);
document.querySelector('#chat_converse > *').focus();
})().catch(err => console.error(err));```
//Once Connected. We will have below objects in BOT.
```{
"type": "conversationUpdate",
"id": "ERqgImAulq3",
"timestamp": "2020-06-18T07:07:03.448Z",
"serviceUrl": "https://directline.botframework.com/",
"channelId": "directline",
"from": {
"id": "AicCk0YN2Ap9n2Ev1ovbuc-k"
},
"conversation": {
"id": "AicCk0YN2Ap9n2Ev1ovbuc-k"
},
"recipient": {
"id": "BotName#xp113vQdWDM",
"name": "BotName"
},
"membersAdded": [
{
"id": "BotName#xp113vQdWDM",
"name": "BotName"
}
]
}```
//From - section we should get id, name, role. In the "from" object name and role key is missing //and id is present but with auto generated id not actual user id myid.
You're not getting a ConversationUpdate for the user, just the bot. You need to send a ConversationUpdate manually:
const store = window.WebChat.createStore({}, ({ dispatch }) => next => action => {
if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'webchat/join',
value: { language: window.navigator.language }
}
});
}
return next(action);
});
I have applied as below in my code, It helps. May be useful for others
const store = window.WebChat.createStore({}, ({ dispatch }) => next => action => {
if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'webchat/join',
value: { language: window.navigator.language }
}
});
}
return next(action);
});
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({
secret: 'YourKey'
}),
userID : "UserID",
username: "UserName",
store
},
document.getElementById('chat_converse')
);
document.querySelector('#chat_converse > *').focus();
})().catch(err => console.error(err));
It will trigger two time bot activity, One without user info, One with user info. So I did checked at bot side if user info contains name kay then load my initial dialog something like below..It got worked for me. Thanks #mdrichardson
if (membersAdded[cnt].id === context.activity.recipient.id && context.activity.from && context.activity.from.name
&& context.activity.channelId=='directline') {
await dialog.run(context, conversationState.createProperty('DialogState'));
}

Retrieving data from MongoDB ánd MySQL simultaneously

I am trying to retrieve data from my MongoDB database which stores chat conversations. This works fine and returns what I want. However, I only save userIDs in MongoDB, so I need to query profile picture, username etc from my MySQL database. I tried the following:
app.get('/api/retrieveAllChats', (req, res) => {
var Conversation = mongoose.model('Conversation', ConversationSchema);
var ChatMessage = mongoose.model('Message', ChatMessageSchema);
var userID = req.query.userID.toString()
var members = []
var conversationData = []
var retrieveAllChats = new Promise(function(resolve, reject) {
Conversation.aggregate([{ $match: { "members.uID": userID } }, { $lookup: { foreignField: "c_ID", from: "messages", localField: "_id", as: "messages" } }, { "$unwind": "$messages" }, { "$sort": { "messages.t": -1 } }, { "$group": { "_id": "$_id", "lastMessage": { "$first": "$messages" }, "allFields": { "$first": "$$ROOT" } } }, { "$replaceRoot": { "newRoot": { "$mergeObjects": [ "$allFields", { "lastMessage": "$lastMessage" } ] } } }, { "$project": { "messages": 0 } }], function (err, conversations) {
if (err) return handleError(err);
conversations.forEach((conversation, i) => {
return new Promise(function (resolveConversations, rejectConversations) {
var membersPromise = conversation.members.forEach((member, x) => {
return new Promise(function (resolveUserData, rejectUserData) {
getUserData(member["uID"], function(userData) {
members.push({userID: member["uID"], joinDate: member["j"], userName: userData["userName"], userDisplayName: userData["userDisplayName"], userVerified: userData["userVerified"], userProfilePicURL: userData["userProfilePicURL"]})
console.log("userData: ", userData)
conversations[i].members[x].userData = userData
conversationData = conversations
resolveUserData({userID: member["uID"], joinDate: member["j"], userName: userData["userName"], userDisplayName: userData["userDisplayName"], userVerified: userData["userVerified"], userProfilePicURL: userData["userProfilePicURL"]})
})
})
})
resolveConversations()
})
})
resolve()
})
}).catch(error => {
console.log(error)
res.json({ errorCode: 500 })
})
retrieveAllChats.then(function() {
res.header("Content-Type",'application/json');
res.send(JSON.stringify(conversationData, null, 4));
})
})
However, the conversationData array is always empty. So I need a way to resolve the retrieveAllChats promise and pass the data I added to the existing conversations object to return it with all information I need. Any ideas on how I can do this? (getUserData is a function to retrieve the MySQL data, this one works fine and returns what I want)
You are trying to do async operation inside forEach which wouldn't work. You need to either use for...of or Promise.all.
Also, you can make this code much cimpler by using .exec() at the end of running any query or aggregation as that is supported by mongoose. Something like this should work. Make sure you change your routte line to this to tell it is an async function
app.get("/api/retrieveAllChats", async (req, res) => {
core logic
const conversions = await Conversation.aggregate([{"$match": {"members.uID": userID}}, {"$lookup": {"foreignField": "c_ID", "from": "messages", "localField": "_id", "as": "messages"}}, {"$unwind": "$messages"}, {"$sort": {"messages.t": -1}}, {"$group": {"_id": "$_id", "lastMessage": {"$first": "$messages"}, "allFields": {"$first": "$$ROOT"}}}, {"$replaceRoot": {"newRoot": {"$mergeObjects": ["$allFields", {"lastMessage": "$lastMessage"}]}}}, {"$project": {"messages": 0}}]);
for(const conversation of conversations) {
for(const member of conversation.members) {
// add your promise call here and either await it or use then to get the promise value.
}
}

Iterate a JSON array by a key value in react-native

Is there anyway to get a value in an object from a json array. I need to get a value from an object based on another value.
I have my code like:
export default class StandardComp extends Component {
constructor(props) {
super(props)
this.state = {
id: '',
email: 'abc#gmail.com',
dataSource: []
};
}
componentDidMount(){
fetch(someURL, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
})
.then((response) => response.json())
.then((responseJson) => {
this.setState({dataSource: responseJson})
//dunno what to do here
})
.catch((error) => {
console.error(error);
})
}
}
My "responseJson" is something like this. Then providing the key value (abc#gmail.com), how could I get the string "abcdef"?
[
{
"id": "qwerty",
"email": "cat#gmail.com",
"name": "cat"
},
{
"id": "abcdef",
"email": "abc#gmail.com",
"name": "abc"
}
{
"id": "owowao",
"email": "dog#gmail.com",
"name": "dog"
},
]
Thank you in advance.
Find the element that matches email and return the id.
array::find
const data = [
{
"id": "qwerty",
"email": "cat#gmail.com",
"name": "cat"
},
{
"id": "abcdef",
"email": "abc#gmail.com",
"name": "abc"
},
{
"id": "owowao",
"email": "dog#gmail.com",
"name": "dog"
},
];
const findIdByEmail = (data, email) => {
const el = data.find(el => el.email === email); // Possibly returns `undefined`
return el && el.id; // so check result is truthy and extract `id`
}
console.log(findIdByEmail(data, 'cat#gmail.com'));
console.log(findIdByEmail(data, 'abc#gmail.com'));
console.log(findIdByEmail(data, 'gibberish'));
The code will depend on how you get the value abc#gmail.com.
You'll probably need to pass it in as an argument to componentDidMount via a prop? Or extract it to a separate function. It just depends.
Something like this is the most basic way I'd say.
const value = responseJson.filter(obj => obj.email === 'abc#gmail.com')[0].id
Here it is implemented in your class.
export default class StandardComp extends Component {
...
componentDidMount(){
fetch(someURL, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
})
.then((response) => response.json())
.then((responseJson) => {
this.setState({ dataSource: responseJson })
const { email } = this.state
const value = responseJson.filter(obj => obj.email === email)[0].id
})
.catch((error) => {
console.error(error);
})
}
}