在componentDidMount中,我这样做:
apps.forEach(app => {
if (chosenAppId) {
if (app.id === chosenAppId) {
this.setState({ map: this.props.map });
}
}
});
现在,当我在某些功能中执行此操作时:
this.setState({
...this.state.map,
areas: this.state.map.areas.map(el =>
el._id === area._id
? Object.assign(el, {
chooseDevice: false,
editModal: true
})
: Object.assign(el, { chooseDevice: false })
)
});
我具有持久的redux状态,在这种情况下,我希望重新加载this.state.map === this.props.map,但是不知何故,此object.assign改变了我的redux状态,重新加载时,所有内容都保存到了reducer中。
我将其范围缩小为与object.assign有关,因为如果我将.concat()与this.state.map相关,则不会更改redux状态。
如何?我真的不明白。没有调度redux操作,不知道如何发生。
答案 0 :(得分:3)
第Object.assign(el, { chooseDevice: false })
行将使el
突变。
似乎您已将其从道具(因此可能是Redux商店)复制到状态中。因此,它与Redux商店中已经存在的对象引用相同,因此您正在变异商店中的值。
请注意,our official Redux Toolkit package默认包含一个突变检测中间件,当您意外地突变值时,它将引发错误。
答案 1 :(得分:1)
您对问题的根本原因完全正确-Object.assign()
正在突变您在map()
中引用的原始数组项。
要解决此问题,只需摆脱Object.assign()
来改变您的状态:
this.setState({
...this.state.map,
areas: this.state.map.areas.map(el => ({
...el,
chooseDevice: false,
...(el._id === area.id && {editModal: true})
}))
});
答案 2 :(得分:1)
散布一个对象时,它不会克隆现有属性,它只会将它们复制到新对象中,这意味着实例属性将保持不变。
const obj = { numbers: [1, 2, 3], person: { name: 'Foo' } }
const copy = { ...obj };
copy.numbers.push(4);
copy.person.name = 'Bar'
console.log(obj.numbers) // [1,2,3,4]
console.log(obj.person) // { name: 'Bar' }
console.log(copy.numbers) // [1,2,3,4]
console.log(copy.person) // { name: 'Bar' }
请注意,通过更改副本来更新原始对象
因此,当您将州扩展到本地州时,即
...this.state.map
然后在实例属性上使用Object.assign
,您将无意中同时更新Redux状态。
答案 3 :(得分:1)
Object.assign()
方法将所有可枚举的自身属性从一个或多个 source 对象复制到 target 对象。
Object.assign(target, ...sources)
目标
目标对象-修改源属性后将对其应用源属性的对象。
来源
源对象—包含要应用的属性的对象。
Object.assign() - JavaScript | MDN
如果您不希望更改提供的元素,请定位一个空对象。这样,el
和第三个参数中的其他数据将被分配给新对象,而不是覆盖el
的属性。
this.setState(prevState => ({
...prevState.map,
areas: prevState.map.areas.map(el =>
el._id === area._id
? Object.assign({}, el, {
chooseDevice: false,
editModal: true
})
: Object.assign({}, el, { chooseDevice: false })
)
}));
如果您想使它更紧凑,还可以将其转换为对象散布,如果editModal
中的条件更改,请使用内联。
this.setState(prevState => ({
...prevState.map,
areas: prevState.map.areas.map(el => ({
...el,
chooseDevice: false,
editModal: el._id === area._id ? true : el.editModal
}))
}));
编辑:this.state
不应在setState
中使用