For future purposes, this may help too:
It's ok to use setState in useEffect . To do so, however, you need to ensure you don't unintentionally create an infinite loop.
An infinite loop is not the only problem that may occur. See below:
Imagine that you have a component Comp that receives props from parent and according to a props change, you want to set Comp's state. For some reason, you need to change for each prop in a different useEffect:
DO NOT DO THIS
useEffect(() => {
setState({ ...state, a: props.a });
}, [props.a]);
useEffect(() => {
setState({ ...state, b: props.b });
}, [props.b]);
It may never change the state of a , as you can see in this example:
https://codesandbox.io/s/confident-lederberg-dtx7w
The reason this occurs is that both useEffect hooks run during the same react render cycle. When props.a and props.b change at the same time, each useEffect captures the same stale state value from before the update. As a result, when the first effect runs, it calls setState({ ...state, a: props.a }) . Then, the second effect runs immediately after and calls setState({ ...state, b: props.b}) with the same stale state value, thereby overwriting the first update. The result is that a never appears to update. The second setState replaces the first one rather than merging the two updates together.
DO THIS INSTEAD
The solution to this problem is to call setState like this:
useEffect(() => {
setState(previousState => ({ ...previousState, a: props.a }));
}, [props.a]);
useEffect(() => {
setState(previousState => ({ ...previousState, b: props.b }));
}, [props.b]);
For more information, check the solution here: https://codesandbox.io/s/mutable-surf-nynlx
With this approach, you will always receive the most updated and correct value of the state.