Why doesn't a useEffect hook trigger with an object in the dependency array?

Viewed 1610

I'm noticing something really strange while working with hooks, I've got the following:

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

const [dependency1, setDependency1] = useState({});
const [dependency2, setDependency2] = useState([]);

useEffect(() => {
  console.log("dependency 1 got an update");
}, [dependency1]);

useEffect(() => {
  console.log("dependency 2 got an update");
}, [dependency2]);

setInterval(() => {
  setDependency1(prevDep1 => {
    const _key = "test_" + Math.random().toString();
    if (prevDep1[_key] === undefined) prevDep1[_key] = [];
    else prevDep1[key].push("foo");
    return prevDep1;
  })
  setDependency2(prevDep2 => [...prevDep2, Math.random()]);
}, 1000);

for some reason only the useEffect with dependency2 (the array where items get added) triggers, the one with dependency1 (the object where keys get added) doesn't trigger..

Why is this happening, and how can I make it work?

3 Answers

React will only check for reference equality when deciding a dependency changed, so if the old and new values pass a === check, it considers it unchanged.

In your first dependency you simply added a key to the existing object, thus not changing the actual object. The second dependency actually gets replaced altogether when spreading the old values into a new array.

setInterval(() => {
    setDependency1(prevDep1 => {
      const _key = "test_" + Math.random().toString();
      return {...prevDep1, [_key]: [...(prevDep1[_key] || []), 'foo']   }
    })
    setDependency2(prevDep2 => [...prevDep2, Math.random()]);
  }, 1000);

State should be updated in an immutable way.

You're returning an assignment statement here:

setDependency1(prevDep1 => prevDep1["test_" + Math.random().toString()] = ["foo"]);

You should return an object. Maybe something like:

setDependency1(prevDep1 => ({ ...prevDep1, ["test_" + Math.random().toString()]: ["foo"] }));
Related