useEffect dependency array and ESLint exhaustive-deps rule

The way to look at it is every render has its own effect. If the effect will be the same with a particular set of values, then we can tell React about those values in the dependencies array. Ideally, a component with the same state and props, will always have the same output (rendered component + effect) after its render and effect is done. This is what makes it more resilient to bugs.

The point of the rule is that, if the deps DO change, the effect SHOULD run again, because it is now a different effect.

These 3 links also give more insights about this:

  • https://github.com/facebook/react/issues/14920#issuecomment-471070149
  • https://overreacted.io/a-complete-guide-to-useeffect/
  • https://overreacted.io/writing-resilient-components/

Actually the rule is very straightforward: Either pass an array containing all dependencies, or don't pass anything. So I guess the rule isn't dumb, it just doesn't know if the dependencies are going to change or not. So yes, if you are passing an array of dependencies it should contain ALL dependencies, including those you know for a fact that will not change. Something like this will throw a warning:

useEffect(() => dispatch({ someAction }), [])

And to fix this you should pass dispatch as a dependency, even though it will never change:

useEffect(() => dispatch({ someAction }), [dispatch])

Don't disable the exhaustive deps rule, as mentioned here


UPDATE 05/04/2021

As addressed here. This is no longer necessary since eslint pull #1950.

Now referential types with stable signature such as those provenients from useState or useDispatch can safely be used inside an effect without triggering exhaustive-deps even when coming from props