DEV Community

Cover image for Avoid ignoring react-hooks/exhaustive-deps linting warnings
Muhammad Haseeb
Muhammad Haseeb

Posted on • Edited on

Avoid ignoring react-hooks/exhaustive-deps linting warnings

This post is inspired by the conversation on this github issue which was shared by a colleague in one of our technical meeting. There are so many other cases discussed here so its worth reading.

Rationale

While working with a react hook, you must have been in a situation when you get this linting warning react-hooks/exhaustive-deps. You try to add the dependency to the array and may ended up in an infinite loop or any unexpected behavior;

For example:

You have a state count in your component and you want to increment it only once. Most likely you will write in this way.


 javascript
  useEffect(() => {
    setCount(count + 1);     
  }, []);


Enter fullscreen mode Exit fullscreen mode

This will give you a warning that React Hook useEffect has a missing dependency: 'count'. Either include it or remove the dependency array

You have an easy exit: that is to ignore the error by disabling the rule;


 eslint-disable-next-line

Enter fullscreen mode Exit fullscreen mode

 javascript
useEffect(() => {
  setCount(count + 1);
  // eslint-disable-next-line
}, []);


Enter fullscreen mode Exit fullscreen mode

**It worked - Great job!!! 👏** But wait;

Image

The design of useEffect forces you to confront it. You can of course work around it, but the default is to nudge you to handle these cases. Instead of disabling these warnings, I've found it worth finding a way to accommodate the dependency array requirements.

In most situations its practically possible and I will talk about some very common use-cases here.

For state dependencies

In the preceding example, you can get rid of that warning using a callback in your setCount method because count will no longer be a dependency 😊


 javascript
useEffect(() => {
  setCount((count) => count + 1);
}, []);


Enter fullscreen mode Exit fullscreen mode

image

Another drawback off adding // eslint-disable-next-line could be that it will not warn you about future dependencies. i.e If you made some changes in that hook which has a dependency but you forgot to add it in the dependency array, you will not get a warning now as you already have disabled that. This could lead to unexpected behavior and even break your app.

For function dependencies

When you use any function in the useEffect hook.
Let’s consider you have a function that uses name as argument and does something. You will get an es-lint warning for not adding the function in the dependency array.


 javascript
const functionName = (name) => {
  // do something
};

useEffect(() => {
  functionName(name);
}, [name]);


Enter fullscreen mode Exit fullscreen mode

But, even adding it directly to the dependency wont fix it and you will get another warning that you have just caused an infinite loop because someFunction has a different reference on each render. So whats the fix?

The solution here is likely to wrap that function in a useCallback hook because useCallBack will return a memoized callback. It makes certain that the function doesn’t change references between renders.


 javascript
const functionName = useCallback((name) => {
  // do something with count
}, []);

useEffect(() => {
  functionName(name);
}, [name, functionName]);


Enter fullscreen mode Exit fullscreen mode

PS:

As per official useCallBack docs make sure that every value referenced inside the callback should also appear in the dependencies array.


Here is another use-case I saw on the same github issue related to useCallBack, where a user will add an email and invite those email to the app. It potentially fix the deps into [emails, props]. Whereas, actually it needs to update the function reference only when onSubmit change and not any other prop.


 javascript
const handleSubmit = React.useCallback(
  () => {
    props.onSubmit(emails);
  },
  [emails, props]
);


Enter fullscreen mode Exit fullscreen mode

This is because technically props.onSubmit() passes props itself as this to onSubmit call. So onSubmit might implicitly depend on props and the best practice is always de-structuring.

Valid-Case

I also want to talk about one of the legitimate cases that I found on the same thread, where you may have to disable extraneous dependency warning


javascript
useEffect(() => {
window.scrollTo(0, 0);
}, [activeTab]);
Enter fullscreen mode Exit fullscreen mode




Summary

Its very common to disable/ignore react-hooks/exhaustive-deps linting warnings in most cases. Probably you actually want to fire the hook when the dependency 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. So, you should try to fulfill react hook dependency requirements with given ways instead disabling.


Hit the ❤️ if it was helpful and you learn something new

Top comments (1)

Collapse
 
mithilesh44 profile image
Mithilesh

With react version 19 there will not be a need for useCallback() hook because the react compiler will take care of it. So i think the react team are already aware about it and in react 19 they will fix this exhuastive usage of useMemo and useCallback everywhere in your codebase.