Yannick
Yannick

Reputation: 1600

React hooks - trigger useEffect when a nested property changes in a collection of objects

A page displays a list of objects [{name:, age:}, ...] A second page allows to update the name of a particular object. Then using hooks, how should I implement useEffect() so the list on the front page updates only when a name change has been detected?

const [objects, setObjects] = useState([]);

useEffect(()=> {
  getAllObjects()
},[getAllObjects, objects]);

Upvotes: 44

Views: 58159

Answers (5)

snowyBunny
snowyBunny

Reputation: 445

// using JSON.stringify(object)
useEffect(() => {
   // your code here...
}, [JSON.stringify(dependencyObject)]);

The best solution is to use JSON.stringify(object) as it won't lead to any error on the initial load or warning about the changes in size of dependency variables.


// using spread operator
useEffect(() => {
   // your code here...
}, [ ...Object.values(dependencyObject) ]);

The solution with spread operator on object keys and values will cause an error if the object is null/undefined in the initial load.

/* 
  Also if you make a custom function that either returns the 
  values or empty array then React will give a warning about 
  the size change in dependency array.
*/
const getDependencies = (addressType: Address) => {
if (addressType) {
  return Object.values(addressType);
}
return [];
}

useEffect(() => {
   // your code here...
}, [ ...getDependencies(dependencyObject) ]);

So use JSON.stringyfy(object). it won't give any errors when the object is undefined or null and React won't complain about the change in size of dependency variables.

Upvotes: 5

Elihu Del Valle
Elihu Del Valle

Reputation: 396

None of the previous answers worked for me

This is my solution:

const [objects, setObjects] = useState([]);

useEffect(()=> {
  getAllObjects()
},[getAllObjects, ...Object.values(objects)]);

This way you are extracting the values from your state and once any of these values change the useEffect will be triggered

Upvotes: 1

Rayees Pk
Rayees Pk

Reputation: 2993

Please add JSON.stringify for the nested object.

useEffect(()=> {
   getAllObjects()
},[getAllObjects, JSON.stringify(objects)]);

Upvotes: -5

Alexander
Alexander

Reputation: 7842

Check https://dev.to/aileenr/til-you-can-watch-for-nested-properties-changing-in-react-s-useeffect-hook-26nj

One can just do:

useEffect(()=> {
      // do something
}, [values.name])

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. A workaround in this scenario is to check if prop exists inside the hook

useEffect(()=> {
    if (values?.name) {
        // do something
    }
}, [values])

Upvotes: 7

Shubham Khatri
Shubham Khatri

Reputation: 281774

Instead of passing the entire object to the dependency array, make sure that you only pass name. Which you can do by returning the names

const [objects, setObjects] = useState([])

useEffect(()=> {
      getAllObjects()
}, [getAllObjects, ...objects.map(item => item.name)])

Upvotes: 38

Related Questions