React 是否在内部创建了 prevState 的深拷贝或浅拷贝?

Does React create a deep or shallow copy of prevState internally?

我刚刚开始编程,最近用 React 编写了我的第一个应用程序,虽然它确实有效,但我不确定我是否正确处理了我的内部状态。我的问题是 setState 方法是否一定会创建 "prevState" 的不可变深层副本?举个例子:

 menuAddRecHandler = () => {
    this.setState((prevState) => {
      const updatedState = {...prevState};
      const dayInd = updatedState.menu.recipes.findIndex(item => item.dayNum === updatedState.menuInternal.currentDay);
      updatedState.menu.recipes[dayInd].recList.push({
        name: prevState.menuInternal.menuRecSelect,
        portions: prevState.menuInternal.menuNumPortInput
      });
      return updatedState;
    })
  }

在我的处理程序中,我将一个对象推送到 updatedState 对象的嵌套数组中,该数组是由展开运算符从 prevState 复制过来的。现在我知道展开运算符只生成一个浅拷贝,但是 setState 方法内部提供的 prevState 是否也很浅,这是否意味着我实际上是通过调用这个处理程序直接改变我的状态?如果是这样,我该如何解决这个问题?谢谢。

According to the docs 这根本不是副本

state is a reference to the component state at the time the change is being applied. It should not be directly mutated.

制作深拷贝通常对性能不利,但如果你必须这样做,你可以这样做:

const updatedState = JSON.parse(JSON.stringify(prevState));

你的例子中有很多 "noise" 所以我会保持简单:

state = {  name: `Dennis`, age: 89 }

this.setState((prevState) => {
  return { age: prevState.age + 1 }; 
}); // { name: `Dennis`, age: 90 }

this.setState({ name: `John` }); // { name: `John`, age: 89 }

在class组件中,this.setState与前一个状态浅合并,prevState是实际状态参考,即:{ name: "Dennis", age: 89 }.

Both state and props received by the updater function are guaranteed to be up-to-date. The output of the updater is shallowly merged with state.

请注意,这不是 the case with functional components(常见错误)。

Unlike the setState method found in class components, useState does not automatically merge update objects.

来自docs

The first argument is an updater function with the signature:

(state, props) => stateChange

state is a reference to the component state at the time the change is being applied. It should not be directly mutated. Instead, changes should be represented by building a new object based on the input from state and props.

如何在不变异的情况下获得相同的结果?

menuAddRecHandler = () => {
  this.setState((prevState) => {
    return {
      ...prevState,
      menu: {
        ...prevState.menu,
        recipes: prevState.menu.recipes.map((item) => {
          if(item.dayNum === prevState.menuInternal.currentDay) {
            return {
              ...item,
              recList: [
                ...item.recList,
                {
                  name: prevState.menuInternal.menuRecSelect,
                  portions: prevState.menuInternal.menuNumPortInput
                }
              ]
            }
          }
          return item;
        })
      }
    }
  });
}

这显然很容易出错,这个想法是为了减少更深层次的状态。 Redux offer some tips for normalizing state.

的文档

您还可以查看不可变状态库,例如 ImmutableJS or Immer