I have two useEffect
hooks, which will both run on change in startTime/endTime
state.
useEffect(() => { if (selectedProduct) { fetch(...) .then(res => res.json()) .then(res => setMyState(res.data)); } }, [selectedProduct, startTime, endTime]); useEffect(() => { if(selectedStep){ console.log(myState); //this runs twice, once for the old state and once for the new state, after above useEffect's setState is complete } }, [selectedStep, startTime, endTime, myState]);
I understand from looking around that this is probably because React does some sort of batching for performance gain such that setState
is async in nature. Also, the fetch
call would be async too, so it will take time to set the new state.
From what I have searched, I see that there is a callback
for class based
React components using setState
but as I am using hooks, I am not sure what to do. I can move the second useEffect
code in the first one, but that would require some ugly if-else
conditions as I need to check if selectedStep
has not changed, and then I can use the res.data
directly.
Is there a better way of doing this?
Advertisement
Answer
It’s not batching of operations or anything like that, it’s just that that’s how it works: When startTime
or endTime
changes, each of those hooks is executed, and since the first changes myState
, your second one gets called again for that change.
A few options for you
Combine the hooks as you described, even if it involves conditional logic.
Depending on what you’re doing with
myState
, you might make the second hook use the callback form ofsetMyState
which receives the current state value as a parameter.(If possible) Remove the dependencies on other state items in your second
useEffect
so that it only gets executed whenmyState
changes
Despite your saying it’ll involve some if
/else
, I’d lean toward #1 if you can’t do #3.