Email - harun.bspt2014@gmail.com Phone - +8801717615827

useEffect-compare-array-in-second-argument-shallow

 Problem – Effect re-run endlessly when using an array as a second argument for useEffect which is not the case when I use the array.length instead

CodeSandbox : codesandbox.io/s/nrwq08p9zj (you can see that the console keeps logging into console)

The below will continue to log ‘getting array’ infinitely in the console.

const getArray = () => [
  { id: "123", value: "some value" },
  { id: "456", value: "another value" }
];

function Child({ array }) {
  useEffect(() => {
    console.log("getting array");
    getArray();
  }, [array]);

  return (
    <div>
      <h1>Hello!</h1>
      {array.length > 0 &&
        array.map(item => <li key={item.id}>{item.value}</li>)}
    </div>
  );
}

Child.defaultProps = {
  array: []
};

Child.propTypes = {
  array: PropTypes.arrayOf(
    PropTypes.shape({
      id: PropTypes.string,
      value: PropTypes.string
    })
  )
};

function App() {
  const [array, setArray] = useState([]);

  setTimeout(() => setArray(getArray()), 500);

  return <Child array={array} />;
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Guidance on how to resolve this – This is the expected behaviour. the default behaviour of useEffect’s second argument is to do a shallow equal check on what’s passed in; since you’re passing a new array (since getArray returns a new array instance each time) as the first element of the array (ie, it’s a nested array), comparing on it will miss the cache and run the effect again. You can work around this by either making sure you pass the same instance of the array, or by passing values that can be compared shallowly in the array.

useEffect(() => {
  /* ... */
}, [someHashingFunction(array)]);
// we could use a hashing function (like murmur3 or md5) to generate a value to compare against

This also explains why it doesn’t re-render when you use array.length, since it doesn’t change between renders; however that is buggy, because it also means your component won’t re-render when the array contents change, but with the same length. Don’t do this.

For each of the three most common lifecycle methods (componentDidMount, componentDidUpdate, componentWillUnmount), I will demonstrate a class style implementation

componentDidMount

// First the class component Example
class Example extends React.Component {
  componentDidMount() {
    console.log("I am mounted!");
  }
  render() {
    return null;
  }
}

// With hooks the same above Example component
function Example() {
  useEffect(() => console.log("I am mounted"), []);
  return null;
}

The second argument is an array of values (usually props).

If any of the value in the array changes, the callback will be fired after every render. When it’s not present, the callback will always be fired after every render. When it’s an empty list, the callback will only be fired once, similar to componentDidMount.

componentDidUpdate

componentDidMount() {
  console.log('mounted or updated');
}

componentDidUpdate() {
  console.log('mounted or updated');
}
useEffect(() => console.log('mounted or updated'));

There is not a straight forward implementation in hooks to replace componentDidUpdate. The useEffect function can be used to trigger callbacks after every render of the component including after component mounts and component updates. However this is not a big problem since most of the time we place similar functions in componentDidMount and componentDidUpdate.

Further Reading

Further Reading

Dr. Harun
Dr. Harun

Dr. Md. Harun Ar Rashid, MPH, MD, PhD, is a highly respected medical specialist celebrated for his exceptional clinical expertise and unwavering commitment to patient care. With advanced qualifications including MPH, MD, and PhD, he integrates cutting-edge research with a compassionate approach to medicine, ensuring that every patient receives personalized and effective treatment. His extensive training and hands-on experience enable him to diagnose complex conditions accurately and develop innovative treatment strategies tailored to individual needs. In addition to his clinical practice, Dr. Harun Ar Rashid is dedicated to medical education and research, writing and inventory creative thinking, innovative idea, critical care managementing make in his community to outreach, often participating in initiatives that promote health awareness and advance medical knowledge. His career is a testament to the high standards represented by his credentials, and he continues to contribute significantly to his field, driving improvements in both patient outcomes and healthcare practices.

Translate »
Register New Account