单击下面的测试按钮时,对象的 2 个副本被推入阵列。
谁能解释为什么会发生这种情况?我只期望 1 个对象。
class Testing extends React.Component {
state = {
things: []
}
test = () => {
this.setState(prevState => {
const things = [...prevState.things];
things.find(x => x.id === '39cc413f-a25c-409d-ad09-05df5b4b28b6')['stats'].push({
mana: 100,
health: 1
});
return { things};
});
}
componentDidMount = () => {
this.setState({
things: this.state.things.concat({
id: '39cc413f-a25c-409d-ad09-05df5b4b28b6',
stats: [],
enemies: []
})
});
}
render() {
const { things } = this.state;
return (
<React.Fragment>
<button type="button" onClick={this.test}>Test</button>
<br />
{things.map((thing, i) => <div key={i}>{JSON.stringify(thing)}</div>)}
</React.Fragment>
);
}
}
ReactDOM.render(<React.StrictMode>
<Testing />
</React.StrictMode>, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div class='react'></div>
我假设您使用的是严格模式。在许多情况下,React 会触发两次状态回调,以捕获生产中可能发生的状态管理错误。
特别是 this.setState 的回调参数运行了两次——第一个结果被丢弃,第二个结果被使用。这应该没有区别,但在这里这样做是因为底层状态正在发生变化:事物只是 prevState.things 的浅拷贝,因此使用 .find 然后改变找到的对象会导致明显的双重更新。- 罗宾·齐格蒙德
见:
您可以使用 JSON.parse(JSON.stringify(thingy)) 轻松地(不一定是高效的)深度复制数组,如下所示。
[如果 id 不存在,还添加了错误处理。]
class Testing extends React.Component {
state = {
things: []
}
test = () => {
this.setState(prevState => {
console.log(prevState)
let things = JSON.parse(JSON.stringify(prevState.things));
const index = prevState.things.findIndex(x => x.id === '39cc413f-a25c-409d-ad09-05df5b4b28b6');
if (index !== -1) {
let statsCopy = [...things[index].stats, {
mana: 100,
health: 1
}];
//console.log(statsCopy)
things[index]["stats"] = [...statsCopy];
return {
...prevState,
things: [...things]
}
}
return {
...prevState
}
});
}
componentDidMount = () => {
this.setState({
things: this.state.things.concat({
id: '39cc413f-a25c-409d-ad09-05df5b4b28b6',
stats: [],
enemies: []
})
});
}
render() {
const {
things
} = this.state;
return ( <
React.Fragment >
<
button type = "button"
onClick = {
this.test
} > Test < /button> <
br / > {
things.map((thing, i) => < div key = {
i
} > {
JSON.stringify(thing)
} < /div>)} < /
React.Fragment >
);
}
}
ReactDOM.render( <
React.StrictMode >
<
Testing / >
<
/React.StrictMode>, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div class='react'></div>
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句