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

23,978

Solution 1

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)])

Solution 2

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])
Share:
23,978

Related videos on Youtube

Yannick
Author by

Yannick

Software Developer ReactJS React Native Typescript Rust...

Updated on July 09, 2022

Comments

  • Yannick
    Yannick almost 2 years

    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]);
    
  • Yannick
    Yannick about 5 years
    Thanks, I am glad I asked I wouldnt have figured this trick out myself. Is it considered best practice though? The create-react-app linter raises a warning: React Hook useEffect has a spread element in its dependency array. This means we can't statically verify whether you've passed the correct dependencies. Do you know if I can get rid of it without disabling the linting ?
  • Shubham Khatri
    Shubham Khatri about 5 years
    Maybe use objects.map(item => item.name).concat([getAllObjects]) for dependency array
  • Yannick
    Yannick about 5 years
    Ok thanks, I tried... the linter then complained the expression is too complex and I should extract it to a variable... what I did and then pass the variable to the deps array... now it's telling me that the variable is a unnecessary dep... there might be a flaw in my design here...
  • Shubham Khatri
    Shubham Khatri about 5 years
    @Yannick Since you know what you are doing, you can disable the lint rule for this particular line
  • Yannick
    Yannick about 5 years
    Ok thanks, I'll start with that! Still looking forward to finding an answer that would follow Hooks best practices.... If it exists!
  • keif
    keif over 4 years
    In my case, I needed an object, ended up with: ...Object.keys(myObj).map(key => myObj[key])
  • Wild Goat
    Wild Goat almost 4 years
    Object.keys(objects).map(key => ${key}_${objects[key]}).join("_") this give you a single string which always going to be different when key or value changes in the object. Works well.
  • Nikhil sHETH
    Nikhil sHETH over 3 years
    Really gr8 one, Thanks a lot
  • iPzard
    iPzard over 3 years
    Excellent answer!
  • untitled
    untitled about 2 years
    dependency array accepts variables not values