如何更新状态数组中的对象属性
How to update object properties in state array
所以,我正在学习 React 课程。第一次学习这个框架,所以这可能是一个愚蠢的问题。这是我得到的代码,用于更新存储在状态中作为对象数组的对象的 属性。
const [squares, setSquares] = React.useState(boxes)
function toggle(clickedSquare) {
setSquares(prevSquares => {
return prevSquares.map((square) => {
return square === clickedSquare ? {...square, on: !square.on} : square
})
})
}
...但是,我编写的以下代码也可以工作并且看起来更简单,这种方法有什么问题?状态值只是浅层不可变的。据我所知,存储在状态数组中的对象本身是可变的...
const [squares, setSquares] = React.useState(boxes)
function toggle(clickedSquare) {
clickedSquare.on = !clickedSquare.on;
setSquares(prevSquares => [...prevSquares])
}
还要考虑这个示例,其中我有一个数组,其中包含保存在状态中的深层嵌套对象。
[
{
trunk: {
limb: {
branch: {
twig: {
leaf: {
color: "green"
}
}
}
}
}
}
]
我想把那个“绿色”改成“棕色”。它在本文 Handling State in React 中指出...
- Deep cloning is expensive
- Deep cloning is typically wasteful (instead, only clone what has actually changed)
- Deep cloning causes unnecessary renders since React thinks everything has changed when in fact perhaps only a specific child object has changed.
树示例中发生变化的只是叶对象。所以只有那个需要被克隆,而不是数组,而不是整个树或树干对象。这对我来说更有意义。有人不同意吗?
这仍然留下(没有双关语意)通过更新状态数组中的 属性 值而不是克隆具有更改的对象会引入哪些错误的问题?一个具体的例子会非常好,这样我就可以更好地理解我可以优化性能的地方。
clickedSquare.on = !clickedSquare.on;
是状态突变。不要改变 React 状态。
以下代码可能有效的原因是因为它浅复制了 squares
状态数组,这会触发重新渲染并公开变异的数组元素。
function toggle(clickedSquare) {
clickedSquare.on = !clickedSquare.on; // <-- mutation!
setSquares(prevSquares => [...prevSquares]); // new array for Reconciliation
}
在这种特定情况下,它可能不会产生任何不利影响,但变异状态是一把好脚枪,可能会给 debug/diagnose 带来潜在的困难错误,尤其是如果它们的影响要等到几个 children ReactTree 的更深处。
总是使用第一种方法并应用不可变更新模式。当更新 React 状态的任何部分时,即使是嵌套状态,也需要创建新数组和 object 引用才能使 React 的协调过程正常工作。
function toggle(clickedSquare) {
setSquares(prevSquares => prevSquares.map((square) => // <-- new array
square === clickedSquare
? { ...square, on: !square.on } // <-- new object
: square
));
}
在这里,您使用的是 map() 方法,该方法 return 对于该条件只有真或假。
因此,您应该使用 filter() 方法而不是 map() 方法,后者 return 针对该条件过滤数据。
例如:
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 } ]
所以,我正在学习 React 课程。第一次学习这个框架,所以这可能是一个愚蠢的问题。这是我得到的代码,用于更新存储在状态中作为对象数组的对象的 属性。
const [squares, setSquares] = React.useState(boxes)
function toggle(clickedSquare) {
setSquares(prevSquares => {
return prevSquares.map((square) => {
return square === clickedSquare ? {...square, on: !square.on} : square
})
})
}
...但是,我编写的以下代码也可以工作并且看起来更简单,这种方法有什么问题?状态值只是浅层不可变的。据我所知,存储在状态数组中的对象本身是可变的...
const [squares, setSquares] = React.useState(boxes)
function toggle(clickedSquare) {
clickedSquare.on = !clickedSquare.on;
setSquares(prevSquares => [...prevSquares])
}
还要考虑这个示例,其中我有一个数组,其中包含保存在状态中的深层嵌套对象。
[
{
trunk: {
limb: {
branch: {
twig: {
leaf: {
color: "green"
}
}
}
}
}
}
]
我想把那个“绿色”改成“棕色”。它在本文 Handling State in React 中指出...
- Deep cloning is expensive
- Deep cloning is typically wasteful (instead, only clone what has actually changed)
- Deep cloning causes unnecessary renders since React thinks everything has changed when in fact perhaps only a specific child object has changed.
树示例中发生变化的只是叶对象。所以只有那个需要被克隆,而不是数组,而不是整个树或树干对象。这对我来说更有意义。有人不同意吗?
这仍然留下(没有双关语意)通过更新状态数组中的 属性 值而不是克隆具有更改的对象会引入哪些错误的问题?一个具体的例子会非常好,这样我就可以更好地理解我可以优化性能的地方。
clickedSquare.on = !clickedSquare.on;
是状态突变。不要改变 React 状态。
以下代码可能有效的原因是因为它浅复制了 squares
状态数组,这会触发重新渲染并公开变异的数组元素。
function toggle(clickedSquare) {
clickedSquare.on = !clickedSquare.on; // <-- mutation!
setSquares(prevSquares => [...prevSquares]); // new array for Reconciliation
}
在这种特定情况下,它可能不会产生任何不利影响,但变异状态是一把好脚枪,可能会给 debug/diagnose 带来潜在的困难错误,尤其是如果它们的影响要等到几个 children ReactTree 的更深处。
总是使用第一种方法并应用不可变更新模式。当更新 React 状态的任何部分时,即使是嵌套状态,也需要创建新数组和 object 引用才能使 React 的协调过程正常工作。
function toggle(clickedSquare) {
setSquares(prevSquares => prevSquares.map((square) => // <-- new array
square === clickedSquare
? { ...square, on: !square.on } // <-- new object
: square
));
}
在这里,您使用的是 map() 方法,该方法 return 对于该条件只有真或假。 因此,您应该使用 filter() 方法而不是 map() 方法,后者 return 针对该条件过滤数据。
例如:
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 } ]