react-hooks/exhaustive-deps frequently shows a warning for objects returned from custom hooks #34086
Replies: 2 comments
-
Hi, This is a common source of confusion when dealing with react-hooks/exhaustive-deps. The core issue is how React's hook dependency arrays check for changes. They rely on referential equality — meaning if the reference to a value changes, React treats it as different. Let's break down your examples: When you do
obj1 is a stable reference, and obj1.a is a primitive, so no problem. When you do
Here, obj2 is memoized and stable, and obj2.a is a string literal, so fine. But with a custom hook like useDisclosure(), it likely returns a new object on every render, so obj3 is a fresh object each time, even if obj3.onOpen itself is stable or memoized inside. The rule suggests adding the entire obj3 to dependencies because React can’t guarantee that just watching obj3.onOpen is enough. The object might be replaced with a new one, and some other properties could change or cause side effects. Destructuring like this:
Why does the enclosing object’s mutability matter? In short: If your hook returns a new object every render, you either need to: Destructure the properties you want and depend on those directly, or Memoize the entire returned object inside the hook to keep references stable. |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
There's a lot of content on this but I'm confused 😵💫. The eslint rule
react-hooks/exhaustive-deps
throws a warning when we put nested properties from hook-returned objects into the dependency array.Here's the problem:
One of the issues where this is described is #24300 . @gaearon wrote that the reason this is forbidden has to do with
useDisclosure
's return value needing to be immutable.However, this does not make sense. In the example above:
obj1
is just as mutable asobj3
. And overall, I fail to see why the mutability of the enclosing object matters in the first place. In my head, it is the reference to the functiononOpen
that matters. The fact that I'm allowed to de-structure the value further illustrates this:I'm struggling to understand this and can't find any clear reason why we can't have a nested property from a hook-returned object as a dependency.
Beta Was this translation helpful? Give feedback.
All reactions