Every 5 seconds there is some data coming from the long poll, and I want my component to dispatch an operation every time an item of the array (or the array length itself) changes. How do I prevent useEffect from going into an infinite loop when passing an array as a dependency, but still manage to schedule some operations if any value changes?
useEffect(() => { console.log(outcomes) }, [outcomes])
Where outcomes
is an ID array, such as [123, 234, 3212]
. Items in the array may be replaced or removed, so the total length of the array may (but does not necessarily) remain the same, so passing outcomes.length
as a dependency is not the case.
outcomes
Custom selector from reselect:
const getOutcomes = createSelector( someData, data => data.map(({ outcomeId }) => outcomeId) )
Using JSON.stringify() or any deep comparison method may be less efficient, if you know the shape of the object ahead of time you can write your own effect hook to trigger a callback to your custom equality function based on the result.
useEffect
works by checking if each value in the dependencies array is the same as the value in the previous render and executing a callback if one of them is not. Therefore, we only need to useuseRef
to retain the data instance we are interested in, and only allocate a new instance to trigger the effect when the custom equality check returnsfalse
.usage
Going a step further, we can also reuse this hook by creating an effects hook that accepts a custom equality function.
usage
Live Demo
You can pass
JSON.stringify(outcomes)
as a list of dependencies:Learn MoreHere