Skip to content
Advertisement

How to get the correct state in an useEffect hook, after another useEffect hook modifies the same state?

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

  1. Combine the hooks as you described, even if it involves conditional logic.

  2. Depending on what you’re doing with myState, you might make the second hook use the callback form of setMyState which receives the current state value as a parameter.

  3. (If possible) Remove the dependencies on other state items in your second useEffect so that it only gets executed when myState changes

Despite your saying it’ll involve some if/else, I’d lean toward #1 if you can’t do #3.

Advertisement