DEV Community

Cover image for Help! I have useEffect dependency array warnings
lmeromy
lmeromy

Posted on

Help! I have useEffect dependency array warnings

Running into issues when using useEffect in a React component is nothing new. How to understand and properly use useEffect (including my current issue) has been extensively covered by people like Dan Abramov.

And yet, here I am! This is a short, hopefully clear explanation for the benefit of my future self when I inevitably forget what I've just learned.

The problem:
Including an object as a dependency in my useEffect dependency array causes infinite looping.

const params = {name: 'myName', id: 1}
<MyComponent params={params}/>

const MyComponent = ({ params }) => {
  const [nodes, setNodes] = useState([]);

  useEffect(() => {
    const res = axios.get('/my/request/url', params );
    setNodes(res);
  }, [params]);
}
Enter fullscreen mode Exit fullscreen mode

And removing those dependencies from my useEffect dependency array brings up this warning:
React Hook useEffect has a missing dependency: 'params'. Either include it or remove the dependency array.

The solution(s):

  1. Think about whether or not I actually need the object in my useEffect block (answer: probably yes or I wouldn't have put it in the dependency array in the first place, but good to be thoughtful).
  2. If I do need the object, try to specify the values I am using, don't just reference the object or the array as whole.
useEffect(() => {
    const res = axios.get('/my/request/url', { name: params.name, id: params.id, });
    setNodes(res);
  }, [params.name, params.id]);
Enter fullscreen mode Exit fullscreen mode

Another option is to suppress the linter warning, but this is generally not best practice, and may hide other bugs in the future):

useEffect(() => {
    const res = axios.get('/my/request/url', params);
    setNodes(res);
// eslint-disable-line react-hooks/exhaustive-deps
  }, [params]);
Enter fullscreen mode Exit fullscreen mode

Why this issue occurs:
Basically, object equality in Javascript is confusing.

const object1 = { id: 1 };
const object2 = { id: 1 };
object1 === object2 // returns false
Enter fullscreen mode Exit fullscreen mode

Objects (including arrays, dates, and plain objects) are compared by their reference. The comparison by reference checks to see if the objects given refer to the same location in memory...and here, they don't.

For my case, params' does not change between renders, but the useEffect only 'sees' theparamsobject it has on a given render and compares it to the previousparams` object from the previous render. And comparing two objects as equal will return false, so the code inside the useEffect will execute again and again.

Other related issues and possible solutions:
I read about another solution using refs explained well in (this article).
It didn't work for my particular situation since I needed the useEffect to execute with the initial props I was passing, but it seems like a useful idea for other scenarios.

Hope this is helpful to someone else!

Latest comments (0)