skip to Main Content

According to https://react.dev/reference/react/useMemo, it says useMemo evaluate deps value with Object.is() function, so if deps values are non primitive like array or object, useMemo calculates the value every render.

Code Sandbox

import { useMemo, useState } from "react";

export default function App() {
  const temp = { a: 1 };
  const [a, setA] = useState({ a: 1 });
  const [aa, setAA] = useState(1);

  const obj = useMemo(() => {
    console.log("obj");
    return { b: a.a };
  }, [a]);

  const obj2 = useMemo(() => {
    console.log("obj2");
    return { b: temp.a };
  }, [temp]);

  return (
    <div className="App">
      <button onClick={() => setA((prev) => ({ a: prev.a + 1 }))}>
        button {a.a}
      </button>
      <div>{obj.b}</div>
      <div>{obj2.b}</div>
      <button onClick={() => setAA((prev) => prev + 1)}>premitive {aa}</button>
    </div>
  );
}

When I click either the first or second button, the console output obj2, which makes sense because variable temp is an object and useMemo calculate value every render.

However, When I click the second button, the console does not output obj even though variable a is an object state.

Why does it happen? I assumed the first useMemo also calculate the value every render, but somehow not

2

Answers


  1. React state is an object actually just like the ordinary JavaScript object. Except that react state can be tracked by the virtual dom and any change to the state can be detected. This is not so with ordinary JavaScript objects. This leads to more complex principles.

    Any state passed to useMemo should also be trackable just like in the virtual dom. But not ordinary objects. useMemo cannot track changes to ordinary objects.

    So while passing dependencies to useMemo, if the dependency is a primitive data type stored in state, it will not be recomputed (for a lack of a better term) but if it is an object stored in state, it will be recomputed (also for a lack of a better term) on every render.

    How about values not stored in state?
    Well you guessed it. Values not stored in state cannot be tracked by useMemo.
    The documentation describes them as non reactive values.

    Login or Signup to reply.
  2. so if deps values are non primitive like array or object, useMemo calculates the value every render

    You’re misunderstanding this part. For non-primitive values, Object.is() compares whether they’re the same reference. So if you do Object.is({a: 1}, {a: 1}) that will return false.

    In this case though, useState() returns the same reference on the next render if it’s not been modified, which is the case when you click the second button because clicking the second button does not modify a.

    If you instead pass {...a} to useMemo(), which will create a shallow clone of a, the useMemo() will be reevaluated on every render.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search