I have two arrays in state:
const [offers, setOffers] = useState([]);
const [redemptions, setRedemptions] = useState([]);
I am updating the properties within this function below:
useEffect(() => {
getData();
}, []);
const getData = () => {
Promise.all([getVenue(), getUserData(), getOffers(), getRedemptions()])
.then(() => {
console.log("OFFERS", offers); // HERE ARE THE OFFERS: [] ??
console.log("REDEMPTIONS", redemptions); // HERE ARE THE REDEMPTIONS: [] ??
})
.catch((error) => {
console.log(error);
})
.finally(() => {
setLoading(false);
});
};
const getOffers = async () => {
const offers = await fetchOffers(id);
setOffers(offers);
};
const getRedemptions = async () => {
const redemptions = await fetchRedemptions(user.uid, id);
setRedemptions(redemptions);
};
However, after all the functions have completed I need access to offers and redemptions and my console logs are returning empty arrays, although my UI is updating with the correct values.
What am I missing here?
2
Answers
Just update the code accordingly!
This will create a shallow copy of the response and set the new value to the state.
Notice how
offers
andredemptions
areconst
. The values of these don’t change in the current execution of your component/function when you call thesetXYZ()
functions. Their values only "change" when your function rerenders/executes again and recreates the variables for that new execution of your component/function. It’s the same reason why if you have a function,foo
, the variables created insidefoo()
are scoped to that execution, and won’t change if you happen to callfoo()
againYou can find out more information on this in the question – The useState set method is not reflecting a change immediately
What you really should do if you want to access
offers
andredemptions
in your.then()
callback is havegetOffers()
andgetRedemptions()
return promises which resolve to theoffers
andredemptions
values respectively. You actually already have functions which do this,fetchOffers()
andfetchRedemptions()
. This way, you can remove thegetOffers()
andgetRedemptions()
functions and call your state setter function in your.then()
callback (note: if you don’t want to call them in the.then()
callback you can keep what you have now, butreturn
theoffers
andredemptions
values from your async functions). This has the added advantage keeping your.then()
from firing after you’ve rendered and using values that might no longer be relevant.Also, you should consider using a cleanup function as part of your
useEffect()
that provides the capability to cancel outgoing requests to avoid trying to update the state of a component when it no longer exists.