我在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" "假 - 假"。有什么想法,为什么它的行为像这样,我怎么能避免这种行为?
答案 0 :(得分:3)
是的,但它并不是一本很深的副本。
新对象包含对旧列表的引用。
这是一个解决问题的伎俩(有更多"正确的"有些人可能会说的方式):
JSON.stringify原作。然后是JSON.parse那个字符串。新对象将是一个深层次的"复制(不确定这是否真的在技术上"深度复制")。它工作正常,除非您的子类型比标准的旧JSON可接受的东西更复杂。
答案 1 :(得分:2)
Object.assign
将创建一个与另一个对象具有相同属性的新对象。其中一些属性是“按值”复制的,而其他属性则是“按引用”复制的。字符串,数字和布尔值是“按值”,而对象(包括日期)是“按引用”,这意味着它们指向同一个对象。
所以,例如,给定:
var otherState = { count: 10 };
var state = { text: "foo", otherState: otherState };
var newState = Object.assign({}, state);
newState.text = "bar";
newState.otherState.count = 9;
newState.text
将为其分配一个全新的字符串,状态不会受到影响。但state
和newState
都引用otherState
的同一个实例,因此当您将count
更新为9时,state.otherState.count
和newState.otherState.count
都是影响。
使用Ojbect.state
时,请使用以下规则:如果您到达第三个属性,则表示您现在处于“共享”状态:
newState.otherState.count = 0;
// ^ ^ ^
// | | |
// 1 2 3
答案 2 :(得分:0)
尝试一下:let newState = state.map(item => Object.assign({}, ...item))
这将创建一个新对象,而无需引用旧对象state
答案 3 :(得分:0)
根据https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign,Object.assign
修改了target
对象,而不是创建一个新对象。
答案 4 :(得分:0)
您可以使用以下内容进行深层复制,然后将 Object.asign
与它一起使用:
const x = { id: "x" },
y = { id: "y" };
x.y = y;
y.x = x;
const cloneX = Object.fromEntries(Object.entries(x));
const cloneChangeX = Object.assign(cloneX, {z: {id: "z"}});
console.log('const x = ', x, '\nconst cloneX = ', cloneX, '\nconst cloneChangeX = ', cloneChangeX);
最后,您可以:
const cloneChangeX = Object.assign(
Object.fromEntries(Object.entries(x)),
{ changekey: changevalue }
);