ReactJs Unable to setSate in componentDidMount from async function - reactjs

I'm calling an async function (getData()) in componentDidMount, and I'm trying to use this.setState with result of that function.
componentDidMount() {
let newData = getData();
newPodData.then(function (result) {
console.log('result', result)
this.setState({result})
})
}
However, I'm having issues getting my state to properly update. Some additional context - I'm trying to set my initial state with data I am receiving from a database. Is my current approach correct? What's the best way to accomplish this? Here's my async function for more context:
const getTeamData = async () => {
const getTeamMembers = async () => {
let res = await teamMemberService.getTeamMembers().then(token => { return token });
return res;
}
const getActiveTeams = async () => {
let res = await teamService.getActiveTeams().then(token => { return token });
return res;
}
const teamMemberResult = await getTeamMembers()
const activeTeamsResult = await getActiveTeams();
// get team member data and add to teamMember object
let teamMemberData = teamMemberResult.reduce((acc, curr) => {
acc.teamMembers[curr.id] = curr;
return acc;
}, {
teamMembers: {}
});
// get team ids and add to teamOrder array
let activeTeamsData = activeTeamsResult.map(team => team.id)
let key = 'teamOrder'
let obj = []
obj[key] = activeTeamsData;
const newObject = Object.assign(teamMemberData, obj)
return newObject;
}
export default getTeamData;

Changing the function inside the then handler to an arrow function should fix it. e.g:
componentDidMount() {
let newData = getData();
newPodData.then((result) => {
console.log('result', result)
this.setState({result})
})
}
But I'll like to suggest a better way to write that.
async componentDidMount() {
let result = await getData();
this.setState({result})
}

Related

How to check if a certain key name exist in json object in React app

I create this custom hook in my React app. It should return a boolean.
const useFetchResponse = (url: string) => {
const [isValid, setIsValid] = useState<boolean>(false);
useEffect(() => {
const fetchResponse = async () => {
const response = await fetch(url);
console.log(response);
const obj = await response.json();
if (response.ok) {
console.log(await response.json());
setIsValid(true);
}
return response;
};
fetchResponse().then((res) => res);
}, []);
return isValid;
};
export default useFetchResponse;
When I log const obj = await response.json(); it returns: {"keyName":"some=key"}.
How do I create a condition to check if response.json() has a key named keyName?
Is that for example console.log('keyName' in obj) // true?
Do you see more things which I can improve and refactor?
Let assume you get response as follow
let response = {
a:'data1',
b:'data2',
c:'data3'
};
Then you can extract keys from object as below:
let keyOnly = Object.keys(response)); // output will be ["a","b","c"]
then you can check if your require value includes on above array or not as below: Assuming if you want to check if "b" is included or not
let checkKey = keyOnly.includes(b)
if you want to check whether an object has a certain property or not, the in operator is fine.
const obj = { a: 1 };
'a' in obj // return true
'b' in obj // return false
About improvements
it's better to save all fetch states, not only valid or not. And you should wrap request with try/catch block. For example:
const [fetchState, setFetchState] = useState('pending');
useEffect(() => {
const fetchResponse = async () => {
try {
setFetchState('loading');
const response = await fetch(url);
console.log(response);
const obj = await response.json();
if (response.ok) {
console.log(await response.json());
setFetchState('success');
}
return response;
} catch (error) {
setFetchState('failed')
}
};
fetchResponse().then((res) => res);
}, []);
return fetchState;
};
fetchResponse(); would be enough. fetchResponse().then((res) => res); is unnecessary.
[optional] You could use libraries to making requests, like an axios. That would be more convenient.
in is slower than below way.
const isValid = obj[`keyname`] !== undefined
Check more detail in here

Why Promise.all is not getting values?

I am using React and inside useEffect I am pulling data but I am getting an emtpy array after all the promises are resolved and cannot figure out why.
Here is the code:
const data = mainnet.FairLaunch.pools.map((pool) => {
const loadingStakingData = async () => {
const stakedValue = await getStakeValue(pool);
const poolDaily = await getPoolDaily(pool);
console.log( { stakedValue, poolDaily }) // all good here and printing what it has to print
return { stakedValue, poolDaily };
};
return loadingStakingData();
});
Promise.all(data).then((values) => {
console.log('value', values) // not logging anything here
setStakingData(values);
}); // always an empty array
Any idea why this is happening?
You might be returning a pending promise in the map function. Maybe try this code instead to return the value
const data = mainnet.FairLaunch.pools.map(async (pool) => {
const stakedValue = await getStakeValue(pool);
const poolDaily = await getPoolDaily(pool);
console.log( { stakedValue, poolDaily }) // all good here and printing what it has to print
return { stakedValue, poolDaily };
});
Promise.all(data)
.then((values) => {
console.log('value', values)
setStakingData(values);
})
.catch(console.error) // Remember to catch errors!!!

React : waiting for a promise

i got a function that uses axios to get info from my backend as follows:
const getDoH = async () => {
const user = JSON.parse(localStorage.getItem("user"));
let config = {
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + user.accessToken,
},
params: {
username: user.username,
},
};
return await axios.get(API_URL + "get", config);
};
Now i want to save these values into a global variable on initiate so i use the initialstate hook like this:
const [initialValues, setInitialValues] = useState(() => {
const initialSwitchState = getDoH().then(
(response) => {
setInitialValues(response.data);
},
(error) => {
console.log(error);
}
);
return initialSwitchState;
});
after that i got a function that takes the values from the db and maps them onto my local variable and this function looks like this:
const setStartValues = () => {
let newValues = initialSwitchState;
let valueArray = Object.entries(newValues).map((v, index) => {
v[1] = initialValues.switchValues[index]
return v
});
newValues = Object.fromEntries(valueArray);
setValues({...newValues});
}
and i want to call this function with a final function that is another initialstate hook like this:
const [values, setValues] = useState(() => {
const initialState = setStartValues();}
but by the time it gets to the line:
v[1] = initialValues.switchValues[index]
the initialValues is still a promise. and i cant see where i have gone wrong as i have used async and wait on my initial getDoH() function.
How can i solve this (wait for the promise) before i try to use the results?
kind regards.
There are two issues here:
First, you need to await getDoH() since that's an async function.
Second, useState() is a synchronous function, so you need to do the await getDoH() inside a useEffect() before you set const [initialValues, setInitialValues] = ...
Tbh i did it with use effect and it comes with its own set of issues. found the best way to do it was:
const [values, setValues] = useState(async () => {
const initialState = await getDoH().then(
(response) => {
let newValues = switchState;
let valueArray = Object.entries(newValues).map((v, index) => {
v[1] = response.data.switchValues[index]
return v
});
newValues = Object.fromEntries(valueArray);
setValues({...newValues});
},
(error) => {
console.log(error);
}
);
return initialState;
});

Why am i getting an undefined output when I try to access value returned from async method

I have the following method which returns an object with 3 fields inside a different file named localStorage:
const getUserProfileData = async () => {
try {
await AsyncStorage.getItem(CONSTANTS.USER_PROFILE).then((item) => {
let retrievedProfile = JSON.parse(item);
return retrievedProfile;
});
} catch (e) {
throw e;
}
};
here is my file profile.js:
useEffect(() => {
const retrieveProfileData = async () => {
let retProfile = await localStorage.getUserProfileData();
console.log("check what: ",retProfile);
};
retrieveProfileData();
}, []);
inside the use effect, when I attempt to log out the result I get an output of:
check what: undefined
I have read other forums on similar problems to this but I can't seem to notice where I'm going wrong?
I think it has to do with you mixing async and .then(). Try this way:
const getUserProfileData = async () => {
try {
const result = await AsyncStorage.getItem(CONSTANTS.USER_PROFILE)
const retrievedProfile = JSON.parse(result);
return retrievedProfile;
} catch (e) {
throw e;
}
};
const getUserProfileData = async () => {
return AsyncStorage.getItem(CONSTANTS.USER_PROFILE);
};
useEffect(() => {
const retrieveProfileData = async () => {
try {
let retProfile = JSON.parse(await localStorage.getUserProfileData());
console.log("check what: ",retProfile);
} catch (error) {
// handle error
}
};
retrieveProfileData();
}, []);

React - How do I get fetched data outside of an async function?

I'm trying to get the data of "body" outside of the fetchUserData() function.
I just want to store it in an variable for later use.
Also tried modifying state, but didn't work either.
Thanks for your help :)
const [userData, setUserData] = useState();
async function fetchUserData () {
try {
const result = await fetch(`/usermanagement/getdocent`, {
method: "GET"
});
const body = await result.json();
//setUserData(body);
return(
body
)
} catch (err) {
console.log(err);
}
}
let userTestData
fetchUserData().then(data => {userTestData = data});
console.log(userTestData);
//console.log(userData);
Use useEffect
async function fetchUserData () {
try {
const result = await fetch(`/usermanagement/getdocent`, {
method: "GET"
})
return await result.json()
} catch (err) {
console.log(err)
return null
}
}
const FunctionalComponent = () => {
const [userData, setUserData] = useState()
useEffect(() => {
fetchUserData().then(data => {
data && setUserData(data)
})
}, []) // componentDidMount
return <div />
}
Ben Awad's awesome tutorial
Example:
it seems that you are making it more complicated than it should be. When you get the response i.e the resolved promise with the data inside the async function, just set the state and in the next render you should get the updated data.
Example:
const [userData, setUserData] = useState();
useEffect(() => {
const getResponse = async () => {
try {
const result = await fetch(`/usermanagement/getdocent`, {
method: "GET"
});
const body = await result.json();
setUserData(body);
} catch (err) {
console.log(err)
}
}
getResponse();
}, [])
console.log(userData);
return <div></div>
Assuming the you need to call the function only once define and call it inside a useEffect or 'componentDidMount'. For using async function inside useEffect we need to define another function and then call it.
When you do
let userTestData
// This line does not wait and next line is executed immediately before userTestData is set
fetchUserData().then(data => {userTestData = data});
console.log(userTestData);
// Try changing to
async someAsyncScope() {
const userTestData = await fetchUserData();
console.log(userTestData)
}
Example:
state = {
someKey: 'someInitialValue'
};
async myAsyncMethod() {
const myAsyncValue = await anotherAsyncMethod();
this.setState({ someKey: myAsyncValue });
}
/*
* Then in the template or where ever, use a state variable which you update when
* the promise resolves. When a state value is used, once the state is updated,
* it triggers as a re-render
*/
render() {
return <div>{this.state.someKey}</div>;
}
In your example you'd use setUserData instead of this.setState and userData instead of {this.state.someKey}

Resources