Redux:为什么做一层状态的浅拷贝是错误的?

IT技术 reactjs redux react-redux
2021-04-29 16:54:02

在阅读有关在 Redux 中更新嵌套状态对象的文档时,我偶然发现了这个常见错误,它指出仅对顶层对象进行浅拷贝是不够的:

function updateNestedState(state, action) {
    // Problem: this only does a shallow copy!
    let newState = {...state};

    // ERROR: nestedState is still the same object!
    newState.nestedState.nestedField = action.data;

    return newState;
}

但我不知道为什么它是不够的,因为从技术上讲它是有效的,正如你在这个小提琴中看到的:https : //codesandbox.io/s/D9l93OpDB

我很乐意对此声明进行进一步的澄清/解释,也很乐意举例说明更新此类状态对象的最佳做法是什么。

谢谢!

1个回答

假设你有一个这样的状态对象:

let state = { a: { b: 1 } };

let cp = { ...state }

cp.a === state.a //true, that means that those are the exact same objects.

那是因为 »inner« 对象 ( state.a) 是cp通过引用添加到的。如果你现在这样做:

cp.a.b = 10;

您也在state.a.b. 所以这里的错误是:如果你想修改state.a.b,那么你必须用一个新的对象替换它,有一个像这样的新值:

let cp = {
  ...state,
  a: {
     ...state.a.b
     b: 2
  }
}

这样做的原因是要求您编写 »pure« 函数,解释一下:

var a = { b: 1 };

//not a pure function
function foo (obj) {
  obj.b++;
  return obj;
}

for (var i = 0; i < 10; i++) foo(a);
//a.b = 11;

所以对象被修改每次调用foo(a)都会产生不同的输出并修改一个全局变量。

以上可能会导致您遇到非常讨厌的错误,这些错误很难找到并防止您遇到这种情况,更喜欢下面的。

//a pure function
function bar (obj) {
  return {
    ...obj,
    b + 1
  }
}

for (var i = 0; i < 10; i++) bar(a);
//a.b = 2

在那种情况下a没有修改,所以输出bar(a)将始终产生相同的输出。