我有一个 mobx 对象存储,这些对象显示在列表视图中,并在存储值上有一个地图,如下所示:
{ObjectStore.objects.map((obj, index) =>
<ObjectItem
key={obj.id}
obj={obj}
objIndex={index}
...unrelated UI Pros
/>
)}
在 ObjectItem 中有一个 onClick 处理程序,它向该特定对象添加一些新内容:
const handleClick = () => {
ObjectStore.updateObjectbyIdx(objIndex, newData)
}
在商店
updateObjectbyIdx (index, data) {
this.objects[index] = { ...this.objects[index], ...data}
}
两个 React 组件都包装在观察者中。当句柄单击运行时,它会导致父容器重新呈现,然后所有 ObjectItem 组件重新呈现,即使附加数据仅通过索引添加到单个项目。
最初我完全避免使用索引并使用地图更新它,如下所示:
updateObjectbyId (id, data) {
this.objects = this.objects.map(obj => obj.id === id ? { ...obj, ...data} : obj })
}
但我假设由于这是创建一个新的数组引用,因此父容器观察ObjectStore.objects重新渲染。
切换到索引让我期望父级不会重新渲染,因为主数组引用仍然存在,并且由于我在最新点解构了值,因此只有单个 ObjectItem 会重新渲染。
我最终确实让它发挥作用:
updateObjectbyIdx (index, data) {
Object.keys(data).forEach(dataKey => {
this.objects[index][dataKey] = data.dataKey
}
}
但是,当我只想更新数组中单个对象中的数据时,这似乎是一个奇怪的解决方法。
这样做:
updateObjectbyIdx (index, data) {
this.objects[index] = { ...this.objects[index], ...data}
}
您还更新了对该对象的引用,并且由于父组件使用该对象,它将重新渲染。
您可以这样做
Object.assign
:,而不是最后一个解决方案(实际上,这是正确且很好的)
updateObjectbyIdx (index, data) {
Object.assign(this.objects[index], data)
}
这将保留引用并仅更新属性。只需记住深层嵌套的属性、对象、数组即可。要处理它们,您最好使用某种
mergeDeep
函数,Object.assign
不会进行合并,它基本上会覆盖您在自定义循环中所做的所有内容。