Home > Mobile >  have array of objects stored in useState. doesn't update when using the updater function
have array of objects stored in useState. doesn't update when using the updater function

Time:10-02

This is a simplified example of some code I have.

I have a some state, that stores an array of objects

const [characters,setCharacters] = useState([
   {
     val:1,
     bool:false
   },
   {
     val:2,
     bool:false
   },
   {
     val:3,
     bool:false
   },
])

I want to update one of the bool's to true. I then do

setCharacters(prev => {
  prev[2].bool = true
  return prev
})

But it doesn't work. Can anyone explain why?

CodePudding user response:

You need to set a new reference. That is how react detect updates for state variables which are objects.

setCharacters(prev => {
  let prev2=[...prev]
  prev2[2] ={ ...prev2[2], bool : true};
  return prev2;
})

Above code, creates a new reference for the array and the object at 2 index.

CodePudding user response:

This will generate too many re-renders because you have called to times set function which is actually componentDidUpdate().

In this case you have to use useEffect hook to wrap the second set function.

import { useEffect, useState } from "react"

const Test = () => {
    const [characters,setCharacters] = useState([
        {
          val:1,
          bool:false
        },
        {
          val:2,
          bool:false
        },
        {
          val:3,
          bool:false
        },
     ])
     // useEffect - component life-cycle method (componentDidUpdate)
     useEffect(() => {
     // your update functionality
        setCharacters(prev => {
            prev[2].bool = true
            return prev
          })
     },[]); // empty dependency array to render the UI only at first
    return (
        <div>
            {
                characters.map((item, i) => {
                    return (
                        <div key={i}>
                            <p>{item.val}</p>
                            <p>{item.bool ? "true":"false"}</p>
                        </div>
                    )
                })
            }
        </div>
    )
}

export default Test;

I this way you can update the state while page first time rendering.

Your Initial Value for prev[2] was false; But see in image below that your prev[2] = true as you were expecting.

Here is the output on browser:

enter image description here

  • Related