【问题标题】:Cannot assign to read only property 'property' of object '#<Object>'无法分配给对象“#<Object>”的只读属性“property”
【发布时间】:2021-05-12 22:38:34
【问题描述】:

我有这个问题。

带接口:

export interface IDevice {
  id: string,
  selected: boolean
}

通过以下方式创建实例:

let newDevice: IDevice = {
  id: uuid4(),
  selected: false,
} as IDevice;

它以反冲状态添加到数组中,并且在 React 中用于一个函数,其中数组已通过 useRecoilState() 检索。 const [leftList, setLeftList] = React.useState&lt;IDevice[]&gt;([]);

现在它被用于在列表控件上选择设备的处理程序中,出现错误:

...
leftList.map((item: IDevice) => {     
      if (item.id === event.dataItem.id) {
        item.selected = !item.selected;
      }
      return item;
    })
...

我收到错误:无法分配给对象“#”的只读属性“已选择”

即使首先通过 [...leftList] 克隆数组也无济于事。

我迷路了:-) 希望有人能对此有所了解吗?

【问题讨论】:

  • 不应直接修改状态,这是 TS 试图通过将对象设为只读来告诉您的,创建一个新对象并返回 return {...item, selected: item.id === event.dataItem.id ? !item.selected : item.selected}。使用扩展语法克隆数组只会做浅拷贝,不会对其中的对象进行深拷贝

标签: javascript typescript interface instance readonly


【解决方案1】:

不应该直接修改状态,这是您现在通过更新对象在 .map() 方法中所做的。 TS 试图通过将您的对象设为只读来告诉您不要这样做。

相反,您可以使用item 中的所有属性(使用spread syntax ... 完成)创建一个新对象,以及一个新的覆盖属性selected,它将使用项目当前选定项目的否定版本如果 id 与事件的数据项 id 匹配,否则将保留原始选定值:

leftList.map((item: IDevice) => ({
  ...item, 
  selected: item.id === event.dataItem.id ? !item.selected : item.selected
}))

使用扩展语法 ([...leftList]) 克隆数组只会进行浅拷贝,不会对其中的对象进行深拷贝,因此,修改 .map() 中的对象引用是还在修改原来的状态。

或者,不是传播item对象并每次都创建一个新对象(这可能会影响性能,正如@3limin4t0r所指出的那样),您可以只在要修改时返回一个新创建的对象selected 属性:

leftList.map((item: IDevice) => {     
  if (item.id !== event.dataItem.id) return item;
  return {...item, selected: !item.selected};
});

【讨论】:

  • 请注意,此解决方案并不是最佳性能,因为您为数组中的每个元素创建了一个新对象,即使该元素没有更改。您可以添加一个保护子句来解决这个if (item.id !== event.dataItem.id) return item,然后创建具有以下更改的副本。
  • @3limin4t0r 谢谢,好点,我已经修改了代码
猜你喜欢
  • 1970-01-01
  • 2019-04-27
  • 2019-08-30
  • 2023-03-13
  • 2021-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多