You probably shouldn't ignore react-hooks/exhaustive-deps linting warnings
Nick Scialli
August 03, 2021
It’s tempting—we’ve all been there. We get the react-hooks/exhaustive-deps
linting warning about a dependency array in a React hook. We try to add the dependency to the array and then we end up with infinite re-renders or otherwise undesirable behavior.
We have a seemingly-easy out: we can ignore the linting error by placing a // eslint-disable-next-line
right above the dependency array. Here’s a contrived example:
useEffect(() => {
setCount(count + 1);
// eslint-disable-next-line
}, []);
And this indeed works. But I have found out over time that it’s worth the effort to not disable these warnings and, instead, find a way to fulfill the dependency array requirements.
But why?
There are a couple reasons this is worth the effort:
- Your probably actually do want to fire the effect (or whatever hook you’re dealing with) when the variable changes. It might not seem like it at first, but there are probably some edge cases for which your effect logic will fail if you don’t include the variable in the dependency array.
- Once you add the
// eslint-disable-next-line
, you have now given up the opportunity to be warned about future dependencies. If you add a new dependency to the effect, you won’t be warned about forgetting to include it in the dependency array. This could be a big deal and break your app.
How to go about fixing the issue
The more appropriate fix for this warning depends on the situation.
Stateful dependencies
In the aforementioned contrived example, you could likely get away with using a callback in your setCount
method:
useEffect(() => {
setCount((count) => count + 1);
}, []);
Now, count
is not a dependency, so our problem is solved.
Function dependency
Let’s consider the following example in which a function is declared in the body of the component.
const someFunction = (count) => {
// do something with count
};
useEffect(() => {
someFunction(count);
}, [count]);
We get a dependency warning again because someFunction
should be in the dependency array. If we add it directly to the dependency array, we potentially get warned that we have just caused an infinite loop because someFunction
has a different reference on each render.
The fix here is likely to use a useCallback
hook to ensure someFunction
doesn’t change references between renders (unless it itself needs to have dependencies in its dependency array!).
const someFunction = useCallback((count) => {
// do something with count
}, []);
useEffect(() => {
someFunction(count);
}, [count, someFunction]);
When all else fails
When all else fails it’s quite possible you can just do some basic comparison within the effect and bailing out as necessary. In the following example we return
early from the effect if the post id
is undefined
.
useEffect(() => {
if (post.id === undefined) {
return;
}
doSomethingWithPost(post);
}, [post]);
Conclusion
I hope this post has convinced you it’s worth trying to fulfill react hook dependency requirements and has given you some ways to do so.
Nick Scialli is a senior UI engineer at Microsoft.