【问题标题】:Error: Attempting to set key on an object that is immutable and has been frozen错误:尝试在不可变且已冻结的对象上设置键
【发布时间】:2018-02-13 21:11:21
【问题描述】:

我很难追踪与此错误相关的问题,显然这意味着我正在尝试更新不可变对象。奇怪的是,我之前使用过这个实现没有任何障碍,这就是为什么我发现这种行为如此令人困惑。

下面是我使用的方法,它只是改变数组的对象,改变属性并返回更新的状态。正如 here 所引用的,使用 prevState 似乎是绕过不变性的最佳方式。

onCheck = (id) => {
  this.setState((prevState) => {
    prevState.options[id].checked = !prevState.options[id].checked;
    return {
      options: prevState.options,
      dataSource: prevState.cloneWithRows(prevState.options)
    };
  });
}

我还尝试了许多复制 prevState 的变体,但它仍然给我同样的不变性错误。它看起来好像仍然引用而不是复制prevState

 onCheck = (id) => {
    this.setState((prevState) => {
      let options = [...prevState.options];
      options[id].checked = !options[id].checked;
      return {
        options: options,
        dataSource: this.state.cloneWithRows(options)
      };
    });
  }

【问题讨论】:

  • 你正在改变你的函数中的prevState。你不能。您需要克隆prevState.options,更改那个,然后将其设置为新的options
  • 这是完全可以接受的,因为我之前使用过那个实现,更何况它是在文档中直接引用的?除非你可以证明?
  • 如何在文档中引用它?该文档显示了如何将函数传递给setState,它允许您访问 prevState,但在哪个示例中它会改变它?
  • 第一个 sn-p 使用 concat 来操纵 prevState?
  • 不,它没有; concat 返回一个新数组。

标签: javascript reactjs react-native immutability


【解决方案1】:

在您的问题中,您承认您正在改变状态,这是您无法做到的。解决此问题的方法是在修改 prevState.options 之前对其进行克隆。

例如。

var options = Object.assign({}, prevState.options)
options[id].checked
return {
      options,
...

【讨论】:

  • 我仍然遇到相同的不变性问题,它似乎仍在引用状态而不是创建新对象?
【解决方案2】:

正如您的reference 指出的那样,您不应该像您那样直接改变您的数据

prevState.options[id].checked = !prevState.options[id].checked;

在您的链接中,它们通过concat 或“扩展语法”(...)返回一个新数组。所以我建议你先复制你的prevState 并对其进行变异

let state = [...prevState.options];
state[id].checked = !state[id].checked;
...

【讨论】:

  • 我仍然遇到与上述相同的不可变错误?实际上我已经尝试过这种方法,但仍然没有成功。
  • 可以更新prevState.options[id]的格式吗?
【解决方案3】:

我最终找到了解决方案,看来我不仅需要复制数组,还需要复制数组的每个元素。由于数组的各个元素/对象仍然是不可变的/冻结的。

onCheck = (id) => {
    this.setState((prevState) => {
      const newOptions = prevState.options.map((option, index) => {
        let copyOption = {...option};
        if (id == index) {
          copyOption.checked = !copyOption.checked;
        }
        return copyOption;
      });
      return {
        options: newOptions,
        dataSource: this.state.dataSource.cloneWithRows(newOptions)
      };
    });
  }

【讨论】:

    猜你喜欢
    • 2017-02-26
    • 2019-12-28
    • 2019-01-20
    • 2021-05-29
    • 2016-11-11
    • 1970-01-01
    • 1970-01-01
    • 2015-09-30
    • 1970-01-01
    相关资源
    最近更新 更多