Most of the answers here are about how to update a state based on its previous value, but I don't understand how that relates to the question
The useState set method is not reflecting a change immediately
React 18
useState is asynchronous:
When an event that triggers a certain code, occurs, the code starts running, and when it finshes, react will check if there was a state update and if it is the case, only then the value of the useState hook is updated and this leads to a new render in which the new value is availabe.
const [example,setExemple] = useState("") //... <button onClick={() => { const newValue = "new"; setExample(newValue); console.log(example); // output "" and this is normal, because the component didn't rerenderd yet so the new value is not availabe yet }} > Update state </button>
Supposing we have a scenario where we have a state which depends on another state, for example we want to make an API call based on the new value of example every time it is updated and then store the data from response in another state anotherExample.
to achieve so we have two ways:
1. use the value of newValue:
<button onClick={async () => { const newValue = "new"; const response = await axios.get(`http://127.0.0.1:5000/${newValue}`); setExample(newValue); setAnotherExample(response.data); }} > test </button>
since you know that example will receive this value, you can create your logic based on it directly.
2. trigger a useEffect to run each time example is updated by including example in its dependency array:
<button onClick={() => { const newValue = "new"; setExample(newValue); }} > test </button>
useEffect(() => { async function test(){ const response = await axios.get(`http://127.0.0.1:5000/${example}`); setAnotherExample(response.data); } test(); }, [example])
so when example is updated with the event function the component rerenders, we are now in a new different render that once finished, useEffect will run because the value of example is different from what is was during the last render, and since it is a new different render, the new value of example useState hook is available here.
Note: the useEffect hook will run anyway during the first mount.
Which approach better?
while the first method will make all the work in one render 🙂 (a better approach) "React groups multiple state updates into a single re-render for better performance" the second method will do it in two renders, the first when example is updated and the second when anotherExample is updated from inside useEffect 😕
since the component only rerenders when the new value of a useState hook is different from the old one, so when newValue is equal to example the component will not rerender so the useEffect will not run and anotherExample will not be updated 🙂 (a better approach), however in the first method the API is called anyway and we don't want to do that if there is no need also if this happens anotherExample will be updated (anotherExample will receive the same data it already contains because it is the same REQUEST since newValue is equal to example) but if the response in an object or an array then, Object.is method (that the useState hook utilizezs), cannot detect if the new value is equal to the previous one, therefore, the component will rerender 😕
Conclusion:
As it is mentioned above, each one has its advantage, so it depends on the use case.
the second method is more recommended, however the first can be more performant in some cases, for example when you are sure the code will only run when newValue gets a new value using onChange, or maybe when you want to use some other local variables that you will no longer have access to from inside useEffect
console.log("movies =", movies);outsite theuseEffecthook?