React useEffect including the missing dependency will break it

Viewed 225

I'm working on a React App with some useEffect hooks. Let's say I've got the following code:

import React, { useState, useEffect } from 'react';

export default () => {
  const [fooArr, setFooArr] = useState([]);
  const [barObj, setBarObj] = useState({});

  return <h1>{barObj.name + " " + barObj.status}</h1>
}

But, now the problem. fooArr gets changed somewhere else, and I want to update barObj when fooArr changes. I did this as below:

import React, { useState, useEffect } from 'react';

export default () => {
  const [fooArr, setFooArr] = useState([]);
  const [barObj, setBarObj] = useState({});

  // >>> some fetching and setting of 'fooArr' here <<<

  useEffect(() => {
    setBarObj(barObj => {
      let _barObj = { ...barObj };
      _barObj.status = fooArr[1];
      return _barObj;
    })
  }, [fooArr]);

  return <h1>{barObj.name + " " + barObj.status}</h1>
}

However, this gives me the following error React Hook useEffect has a missing dependency: 'barObj' and 'setBarObj'. Either include it or remove the dependency array. I know exactly what this means, but when I include it I get an infinite re-render loop because it keeps updating itself. I've got // eslint-disable-line now next to the dependency array to ignore this. But I feel like that should never be done.

How should I handle this? I would like to not have an error message but to also not have an infinite re-render loop..

Example with more code that is like my code:

useEffect(() => {
  setBarObj(prevBarObj => {
    let _barObj = { ...prevBarObj };
    if(_barObj.status.includes('hello') {
      _barObj.status += "world"
    } else {
      _barObj.status = "other"
    }
    return _barObj;
  })
}, [fooArr])
2 Answers

I think the missing dependency warning is shown because you're shadowing barObj from the state. Try using different argument name and avoid object copying:

useEffect(() => {
    setBarObj(bar => {
      return {...bar, status: fooArr[1]};
    })
  }, [fooArr]);

This should work fine:

useEffect(() => {
  setBarObj(barObj => ({
    ...barObj,
    status: fooArr[1]
  })
}, [fooArr]);

I also recommend you to look into my another post to resolve the issue with fetching data and will avoid missing dependency error.


As per your comment, you can do like:

useEffect(() => {
  if (barObj.status === 'hello') return
  setBarObj(barObj => ({
    ...barObj,
    status: fooArr[1]
  })
}, [fooArr]);

With your updated query, you can use like:

useEffect(() => {
  setBarObj(barObj => {
    const updatedStatus = barObj.status === 'hello' ? (barObj.status + 'world') : fooArr[1]
    return {
    ...barObj,
    status: updatedStatus
  }
}, [fooArr]);
Related