React closure works with missing dependency

Viewed 45

I am trying to understand more about the dependency requirements when using a React hook. Using useMemo as an example, I can increment the counter and the value of dog is rendered as the same value as count. This is odd to me because foo is not referenced as a dependency and from my understanding, this closure should be stale.

From the React docs in regards to useMemo:

every value referenced inside the function should also appear in the dependencies array

It doesn't seem like this^ is a requirement. If someone could help me better understand how the closure works in this particular case, I'd appreciate it.

function App() {
  const [count, setCount] = useState(0);
  
  const foo = useMemo(() => count, [count]);
  const dog = useMemo(() => foo, [count]); // incrementing count updates this value

  return (
    <div className="App">
      {dog}
      <h1>Hello CodeSandbox</h1>
      <h2>You clicked {count} times!</h2>

      <button onClick={() => setCount(count - 1)}>Decrement</button>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}
1 Answers

Because of the way you've set things up, it happens to be that every time count changes, foo also changes. So even though you're checking the wrong variable, there's a 1:1 correspondance between times you want the memoization to break and times it actually breaks.

You shouldn't rely on this though. It is rare that things will be as simple as your example, and so you will easily make mistakes. To reliably get it to work, you should populate the dependency array with the values you actually depend on, not things which are merely synchronized with the values you depend on.

Related