Reputation: 140
It is being mentioned in the react documentation that every thing that is supposed to be changed needs to be present in the dependency array of the useEffect
hook.
I could make use of // eslint-disable-next-line react-hooks/exhaustive-deps
but this is not the ideal way to do it I think.
But what would you do if you want to trigger a Side Effect only when a certain state changes? Not the other things being used to it?
I have a workaround but that doesn't works if you have multiple side effects listening to unique states.
const [state1, setState1] = useState(1);
const [state2, setState2] = useState(2);
const fetchDataWithState = useCallback(() => {
action.fetchData({
state1,
state2,
})
}, [state1, state2])
// Effect to listen to the changes of state1
useEffect(() => {
// Some random work related to state1
fetchDataWithState()
}), [fetchDataWithState, state1])
// Effect to listen to the changes of state2
useEffect(() => {
// Some random work related to state2
fetchDataWithState()
}), [fetchDataWithState, state2])
The above code doesn't work if there are multiple side effects, each specific for a particular state.
If state1
gets changed, the fetchDataWithState
will have a different reference, so it will lead to execute the callback in the second useEffect
which was supposed to triggered only when the state2
changes.
Or should I use // eslint-disable-next-line react-hooks/exhaustive-deps
by not passing fetchDataWithState
it in the dependency array.
Upvotes: 1
Views: 1189
Reputation: 33701
Store the previous value of state1
in a ref
, and only invoke the function if state1
actually changes:
const [state1, setState1] = useState(1);
const [state2, setState2] = useState(2);
const state1PreviousRef = useRef(0); // Any initial value that's the same type as state1, but not the same value
// only invoke action.fetchData if state1 changes:
useEffect(() => {
// state1 changed from last time
if (state1 !== state1PreviousRef.current) {
action.fetchData({state1, state2});
}
// update previous to current
state1PreviousRef.current = state1;
}, [
state1,
state2,
action, // might or might not be necessary, depending on where this is defined (you don't show this in your example)
state1PreviousRef, // not necessary, but **actually** exhaustive
]);
Upvotes: 2