Reputation: 11
For my react-app/Express app I am trying to update the component state using the useEffects
to run once when the component renders. Within useEffect
I make a fetch to the express server.
const Favorites = ({ user }) => {
const loggedIn = user.loginname === "" ? false : true;
const [favs, setFavs] = useState([]);
useEffect(() => {
if (loggedIn) {
fetch(`/user/favs/${user.loginname}`)
.then((resp) => resp.json())
.then((data) => {
console.log(data);
setFavs([...data]);
console.log(favs);
});
}
}, []);
return (
<div className="mt-d d-flex justify-content-center">
{loggedIn ? (
<FavoritesList favs={favs} />
) : (
<h3 className="my-2">Please login to use this feature</h3>
)}
</div>
);
};
I make a fetch call on line 11 and am able to print the results on line 14. I then try to update the
component state using setFavs
. My issue is that the state seems to not be updated or maybe
there is some async issue.
const FavoritesList = ({ favs, prop }) => {
const [data, setData] = useState([]);
useEffect(() => {
console.log(favs);
// favs.forEach(item => console.log(item))
}, []);
return <h5>Dummy component</h5>;
};
When I try to print favs on line 16 or print favs within the child(FavoritesList) component it is being passed down to, I get an empty array.
Upvotes: 0
Views: 4127
Reputation: 968
I think above two answers made everyhing clean, here is your lifecycle;
1 -> Favorites component initialized and rendered (state favs = [empty])
2 -> FavoritesList component initialized and rendered (prop favs = [empty])
3 -> FavoritesList useEffect called (console.log(favs) => [empty array])
4 -> Favorites useEffect called (state favs = [now has data])
5 -> FavoritesList component props is updated (prop favs = [has data]
(prop is updated but you didnt call console.log again, after update)
As you can see FavoritesList useEffect called before Favorites useEffect so it called when favs has no data. So if you add favs prop to array in useEffect in FavoritesList component, you will have one more step;
6 -> FavoritesList useEffect called again (console.log(favs) => [has data])
Because useEffect looks for that arrays elements and if one the elements changed it will triger itself again.
Here is your code with working example: codesandbox.io
Upvotes: 0
Reputation: 536
Change your useEffect
on the FavoritesList to:
useEffect(() => {
console.log(favs)
}, [favs])
That way the useEffect
will watch for any changes in the favs
props. Using an empty array means that the useEffect
will only trigger in the first render of the functional component. Meaning that it will not be triggered in any of the props change.
Upvotes: 0
Reputation: 38113
When I try to print favs on line 16 or print favs within the child(FavoritesList) component it is being passed down to, I get an empty array.
You're right, it is an async issue: your call to setFavs
is async and favs
is not yet set on line 16. Calling setFavs
will cause your UI to re-render, eventually.
You won't see it in your other useEffect
on line 35, either, because that useEffect
hook also only runs on first render ([]
), so that value is not there yet on first render. To see all updates to favs
, try adding it to the dependencies array (like [favs]
) or remove the dependencies array altogether.
Upvotes: 1