DEV Community

Aileen Rae
Aileen Rae

Posted on • Updated on • Originally published at aileenrae.co.uk

TIL: You can watch for nested properties changing in React's useEffect() hook

Today I learned: you can watch for nested properties changing in React's useEffect() hook by using dot notation in the dependency array, like so:

// hook runs whenever someValue.someNestedValue is updated
useEffect(()=> {
      // do something
}, [someValue.someNestedValue])
Enter fullscreen mode Exit fullscreen mode

React's useEffect() hook lets you perform a side-effect in a functional component. That is, whenever the component updates, whatever code you put in the useEffect() hook executes.

By default, the hook runs on every component update, which for performance reasons we should avoid:

useEffect(()=> {
    // I run when ANYTHING updates
})
Enter fullscreen mode Exit fullscreen mode

But, we can optionally pass a dependency array as a second argument to tell React to only re-run the hook when the specified dependencies update:

useEffect(()=> {
    // I only run when someValue updates
}, [someValue])
Enter fullscreen mode Exit fullscreen mode

But what about if you have nested data, say an object containing form data, e.g.

const values = {
  name: 'Aileen',
  age: 26,
  city: 'Edinburgh',
  favoriteFood: 'pizza 🍕'
}
Enter fullscreen mode Exit fullscreen mode

What if I want to trigger a side-effect when the user updates just their age, and not when any other value changes?

It seems obvious in hindsight, but you can watch for nested values changing simply by referencing the nested property with dot notation:

useEffect(()=> {
    ageChangeSideEffect(values.age);
}, [values.age])
Enter fullscreen mode Exit fullscreen mode

Additionally, we can trigger the useEffect() hook for deeper nested objects if necessary:

useEffect(()=> {
    // do something
}, [someValue.someNestedValue.someDeeplyNestedValue])
Enter fullscreen mode Exit fullscreen mode

Discussion (4)

Collapse
gabrielmlinassi profile image
Gabriel Linassi • Edited on

It's a fine solution if the object property always exists however if the property is not present at some point you get a reference error. My workaround in this scenario is to check if prop exists inside the hook

useEffect(()=> {
if (values?.age) {
ageChangeSideEffect(values.age);
}
}, [values])

Collapse
abe profile image
Abraham J Gonzalez B

I think is better to use values?.age as a dependency, to avoid to listen all changes in values.

Collapse
milichev profile image
Vadym Milichev

There is no change listening in values because it's an object which is checked for equality by reference. If values is passed to the component as a property and its value is composed as a plain inline object, it will be a new value on each render.

Collapse
yaireo profile image
Yair Even Or

Please un-learn what you learned "today":

github.com/facebook/react/issues/1...