2

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 3

3
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.

Sign up to request clarification or add additional context in comments.

Comments

3

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.

2 Comments

I updated my question so it returns something, but it still does not work..
The last paragraph is no longer valid, but the other point remains true. As long as the old and new props pass a reference equality check === it will not trigger a change.
0

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"] }));

4 Comments

but what if I have to use if-statements?
Remove the short return syntax and use it like a normal function. (e.g prevDep1 => { if (someCondition) { return someValue; } else { return otherValue; } })
that unfortunately doesn't work either, see my updated question please..
Check @Mordechai 's answer. He has already pointed out the problem. The equality check fails because you're returning the same object every time. You could try replacing return prevDep1 with return { ...prevDep1 }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.