Reputation: 7729
Before I asked the question I naturally did a search and found this great post:
I'll show my implementation in a second after I explain a little preamble.
Essentially my problem is the updater function in useState is not updating in sync, it is one behind in the data it gets.
The useState function is passed a object which contains and id, lat and lang.
currentCoords: [{id: 1, lat: 40.74003514370453, lng: -73.76452126968704}]
markers: [{id: 0, lat: 40.74168820148129, lng: -73.76539693565009},…]
0: {id: 0, lat: 40.74168820148129, lng: -73.76539693565009}
1: {id: 1, lat: 40.74003514370453, lng: -73.76452126968704}
currentCoords, should mirror the markers array. As you can see it is "setting" the second.
So I know both because setState and useState are asynchronous, you can't rely on the state being updated.
Now this is what I tried:
useEffect(() => {
if (userMarkers.length === 1) {
userMarkersRef.current = userMarkers[0]; // {id: 0, lat: 40.74168820148129, lng: -73.76539693565009}
setUserCoords(userMarkersRef.current);
setIsRoutingVisibileFalse();
}
if (userMarkers.length === 2) {
userMarkersRef.current = userMarkers[1]; // {id: 1, lat: 40.74003514370453, lng: -73.76452126968704}
setUserCoords(userMarkersRef.current);
}
}, [JSON.stringify(userMarkers)]);
I have included in the useEffect
dependency an array which has been stringified to kick off the hook when it (useMarkers) changes (not to worry that array never goes beyond two items!)
I figured by saving an explicit reference, and then pass it to the updater that would work, but it doesn't :(
This is the setState function, which is saving it to local storage:
setUserCoords: coords => {
setUser({
...user,
currentCoords: [{ ...user.currentCoords[coords.id], ...coords }]
});
},
Upvotes: 1
Views: 265
Reputation: 1371
Essentially my problem is the updater function in useState is not updating in sync, it is one behind in the data it gets.
It looks like whichever user
is being referred to via closure inside of setUser
is stale.
Since your next state depends on your previous state, you can use the other form of setState
to get the most up-to-date snapshot of the previous state.
i.e -
setUserCoords: coords => {
setUser((prevState) => {
return {
...prevState.user,
currentCoords: [{ ...prevState.user.currentCoords[coords.id], ...coords }]
}
});
},
From the React docs:
Both state and props received by the updater function are guaranteed to be up-to-date. The output of the updater is shallowly merged with state.
Upvotes: 1