我在react-redux应用程序中有以下reducer代码:
case 'TOGGLE_CLIENT_SELECTION':
const id = action.payload.id;
let newState = Object.assign({}, state);
newState.list.forEach((client) => {
if (client.id == id) client.selected = !client.selected;
});
console.log(state.list[0].selected + ' - ' + newState.list[0].selected)
return newState;
如果我理解正确的话- Object.assign创建了一个新的对象,但是console.log显示“true - true”或“false - false”。有什么想法吗?为什么它会这样?我如何避免这种行为?
5条答案
按热度按时间0md85ypi1#
Object.assign({}, ...)
创建浅克隆Object.assign({}, state)
将从state
复制属性。字符串,数字和布尔属性是“按值”复制的,而对象属性(包括日期)是“按引用”复制的,这意味着新属性指向与旧属性相同的对象。例如,给定:
newState.text
将被分配一个全新的字符串,状态不会受到影响。但是state
和newState
引用的是otherState
的同一个示例,所以当你将count
更新为9时,state.otherState.count
和newState.otherState.count
都会受到影响:使用
Object.assign
时,请使用三个规则:如果你到达第三个属性,你现在是在“共享”状态下工作:JSON.parse来拯救(?)
Tim建议的一个快速简单的解决方法是使用JSON.stringify:
但这并不是万无一失的。它适用于一些简单的场景,但有很多场景可能会失败。例如,循环引用会破坏JSON.stringify:
拯救自定义克隆代码(?)
如果您知道要克隆的结构,那么您可以使用自己的逻辑来处理复制,而不会陷入无休止的循环:
也可以想象,通过创造性地使用WeakMap,您可以提出一些逻辑,通过跟踪递归和允许深度复制来处理未知的数据结构。
NPM出手相救(?)
不过,只使用use a library可能更容易。
sycxhyv72#
是的,但这不是深度复制。
新对象包含对旧列表的引用。
这里有一个技巧来解决这个问题(有些人可能会说还有更多“正确”的方法):
JSON.字符串化原始的。然后JSON.解析那个字符串。新的对象将是一个“深度”副本(不确定这是否真的是技术上的“深度复制”)。它工作得很好,除非你的子类型比标准的普通旧JSON可接受的东西更复杂。
afdcj2ne3#
试试这个:
let newState = state.map(item => Object.assign({}, ...item))
这将创建一个新对象,而不引用旧对象state
btxsgosb4#
根据https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign,
Object.assign
修改target
对象,而不是创建一个新对象。ecbunoof5#
您可以使用以下命令创建一个深拷贝,然后使用
Object.asign
:最后,您可以执行以下操作: