我有一些似乎有用的代码,但是没有正确。我有一个onChange
处理程序,它向其父组件的setState()
发送一个键和值。
_onAttributeChange(key, value) {
const changes = this.state.changes;
const pushObj = {key: key, value: value};
console.log(pushObj);
if (changes.length === 0) {
this.setState({changes: changes.concat([pushObj])});
} else {
changes.forEach(change => {
if (change.key === key) {
console.log('Update');
} else {
console.log('No update');
this.setState({changes: changes.concat([pushObj])});
}
});
}
}
您可以从此代码中看到我正在根据看起来像{key: 1, value: 'Some Value'}
的键值参数创建对象。如果数组的长度为0,那么目标是将其连接到数组。该部分工作正常。 forEach是我遇到问题的地方。我的目标是遍历状态数组,检查进入的change.key是否与数组中的键匹配,如果是,我想执行更新,否则我想再次连接以将更改添加到数组。
所以有2个问题:
首先,当第一次更改进入时,循环正常工作,并且只使用相同的密钥(即1)为每个连续的更改控制日志Update
。当另一个更改进入时,它首先正常工作并将其连接到数组,但随后使用键2的任何连续更改,它将触发Update和else子句的控制台日志。
其次,如何在不调整状态的情况下循环遍历数组时更新更改?
答案 0 :(得分:2)
答案应该非常简单;只需处理状态的临时副本,一旦完成,用副本替换实际状态。
_onAttributeChange(key, value) {
let changes = this.state.changes.slice();
const pushObj = {key: key, value: value};
console.log(pushObj);
if (changes.length === 0) {
changes = changes.concat([pushObj]);
} else {
changes.forEach(change => {
if (change.key === key) {
console.log('Update');
} else {
console.log('No update');
changes = changes.concat([pushObj]);
}
});
}
this.setState({changes: changes});
}
您对连续更改的问题很可能与setState()
的异步性质有关。每次这样的调用不仅会导致不必要的重新渲染,而且几乎可以肯定会以不必要的方式更新您的状态。
查看官方React文档中有关setState()的内容:
setState()
不会立即改变this.state
但会创建一个 待定状态转换。在调用此文件后访问this.state
方法可以返回现有值。没有 保证调用setState和调用的同步操作 为获得业绩增长而受到批评。
所以基本上它可能会在您实际需要循环中前一次迭代的更新状态时返回“旧”状态值。
此处需要注意的另一个重要事项是,您需要创建正在处理的州属性的 副本 。否则你将直接对状态进行更改,这可能有效,但是不鼓励。
所以基本上总是这样做:
//To copy an array
let arr = this.state.myArray; //wrong. arr still references myArray
let arr = this.state.myArray.slice(); //correct
//To copy an object
let obj = this.state.myObject; //wrong. obj still references myObject
let obj = Object.assign({}, this.state.myObject); //correct
有关slice()和Object.assign()的MDN的更多信息。
另外,请谨慎使用const
。仅当变量必须不可变时才使用它。
TL; DR - 始终先执行所有逻辑,然后提交状态更改。