Home > Enterprise >  How to update object properties in state array
How to update object properties in state array

Time:05-01

So, I'm just going through a React course. Learning this framework for the first time so this is likely a dumb question. Here's code I've been given for updating a property on an object stored in state as an array of objects.

const [squares, setSquares] = React.useState(boxes)

function toggle(clickedSquare) {
    setSquares(prevSquares => {
        return prevSquares.map((square) => {
            return square === clickedSquare ? {...square, on: !square.on} : square
        })
    })
}

...but, the following code I wrote works too and seems simpler, what's wrong with this approach? State values are only shallow immutable. Objects stored in a state array are themselves mutable, as far as I can tell...

const [squares, setSquares] = React.useState(boxes)

function toggle(clickedSquare) {
    clickedSquare.on = !clickedSquare.on;
    setSquares(prevSquares => [...prevSquares])
}

CodePudding user response:

clickedSquare.on = !clickedSquare.on; is a state mutation. Don't mutate React state.

The reason the following code is likely working is because it has shallow copied the squares state array which triggers a rerender and exposes the mutated array elements.

function toggle(clickedSquare) {
  clickedSquare.on = !clickedSquare.on;        // <-- mutation!
  setSquares(prevSquares => [...prevSquares]); // new array for Reconciliation
}

It may not have any adverse effects in this specific scenario, but mutating state is a good foot gun and likely to cause potentially difficult bugs to debug/diagnose, especially if their effects aren't seen until several children deeper in the ReactTree.

Just always use the first method and apply the Immutable Update pattern. When updating any part of React state, even nested state, new array and object references need to be created for React's Reconciliation process to work correctly.

function toggle(clickedSquare) {
  setSquares(prevSquares => prevSquares.map((square) => // <-- new array
    square === clickedSquare
      ? { ...square, on: !square.on } // <-- new object
      : square
  ));
}

CodePudding user response:

Here, You are using map() method which return only true or false for that condition. So, You should use filter() method instead of map() method which return filtered data for that condition.

For Example:

const arr = [
    {
        name: 'yes',
        age: 45
    },
    {
        nmae: 'no',
        age: 15
    }
]

const filterByMap = arr.map(elm => elm.age > 18)
console.log(filterByMap) // outputs --> [ true, false ]

const filterByFilter = arr.filter(elm => elm.age > 18)
console.log(filterByFilter) // outputs --> [ { name: 'yes', age: 45 } ]
  • Related