javascript - 为什么会这样:使用扩展运算符更新状态中的数组元素
问题描述
在阅读 React Cookbook 时,我偶然发现了一个代码片段,当用户在 TODO 列表中检查任务是否已完成时,会调用此函数:
markAsCompleted = id => {
// Finding the task by id...
const foundTask = this.state.items.find(task => task.id === id);
// Updating the completed status...
foundTask.completed = true;
// Updating the state with the new updated task...
this.setState({
items: [
...this.state.items,
...foundTask
]
});
}
UPD:不知何故,我完全错过了foundTask上的扩展运算符。所以真正发生的事情是状态只更新了...this.state.items(已变异),而...foundTask部分没有进入状态,因为它不是有效的传播。
起初它看起来应该向items数组添加一个新元素,而不是更新,所以我去 JS 控制台检查:
state = { items: [{id: '0', done: false}, {id: '1', done: false}] }
upd = state.items.find(obj => obj.id === '0') // {id: "0", done: false}
upd.done = true // also updates object inside the array
state = { items: [...state.items, upd] }
/* Indeed, adds a new element:
items: Array(3)
0: {id: "0", done: true}
1: {id: "1", done: false}
2: {id: "0", done: true}
*/
所以我已经下载了代码并在本地运行它。而且,令我惊讶的是,它奏效了!状态更新没有任何问题,没有出现额外的元素。我在测试时使用 React DevTools 查看实时状态。
我在网上搜索,但找不到任何像书中那样的例子,但有更好的解释。通常所有解决方案都涉及使用 .map() 构建一个新数组,然后替换现有数组(例如https://stackoverflow.com/a/44524507/10304479)。
我在本书代码片段和控制台测试之间看到的唯一区别是 React 使用的是 .setState(),所以这可能会有所帮助。任何人都可以帮助澄清,为什么它有效?
谢谢!
解决方案
Array.find将返回数组中匹配的第一个值。这里数组由对象组成,返回的值将是对对象的引用。
const foundTask = this.state.items.find(task => task.id === id);
这里foundTask
将引用包含在state.items
. 因此,当您修改时,foundTask
您正在修改与state.items
.
例如,
如果this.state.items
是[{ id: 1 }]
,如果你这样做
const foundTask = this.state.items.find(obj => obj.id === 1);
foundTask.id = 2;
console.log(this.state.items); // [{ id:2 }]
在代码中,
this.setState({
items: [
...this.state.items,
...foundTask
]
});
这将使用任务的更新completed
值更新状态。
...foundTask
将在控制台中给您一个错误,因为这foundTask
将是一个对象,并且您将它传播到一个数组中。
这里没有...foundTask
会产生同样的结果。也许没有错误。
推荐阅读
- android - 如何在 Flutter 中为 Android 调用管理音频焦点?
- macos - 使用osxfs的mac docker卷挂载不起作用
- embedded-linux - 从其他文件向 Linux 设备树添加属性
- ruby-on-rails - 如何避免关联模型的 where 查询被触发两次(Rails)?
- html - 防止将网站大小调整到限制以下
- c - 如何正确循环嵌套 switch 语句以提供显示的输出?
- ios - UICollectionView 的帧大小大于 UIScreen 的大小
- css - 响应式水平时间线 - Boostrap 4
- python - 如何检查两个三维numpy数组是否相同?
- python - 在 Pycharm 中,即使在我编辑代码并重新运行算法之后,如何保留我以前的运行结果?