javascript - 无法分配给对象 '#<Object>' 的只读属性 'property'
我有这个问题。
带接口:
export interface IDevice {
id: string,
selected: boolean
}
创建实例方式:
let newDevice: IDevice = {
id: uuid4(),
selected: false,
} as IDevice;
它被添加到 Recoil 状态中的数组中,并在 React 中用于一个函数,该函数中数组是通过 useRecoilState() 获取的。const [leftList, setLeftList]=React.useState<IDevice[]>([]);
现在它被用在一个用于在列表控件上选择设备的处理程序中,这里发生了错误:
...
leftList.map((item: IDevice) => {
if (item.id === event.dataItem.id) {
item.selected = !item.selected;
}
return item;
})
...
我收到错误:无法分配给对象 '#' 的只读属性 'selected'
即使先通过 [...leftList] 克隆数组也没有帮助。
我迷路了:-) 希望有人能对此提供一些见解?
答案#1
状态不应该被直接修改,这正是你现在在 .map() 方法中通过更新对象所做的。TS 正在通过将你的对象设为只读来告诉你不要这样做。
相反,你可以创建一个包含 item 所有属性的新对象(使用展开语法 ... 实现),以及一个新的覆盖属性 selected,如果 id 与事件的数据项 id 匹配,它将使用该项当前 selected 值的取反版本,否则将保持原来的 selected 值:
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};
});
