一个节点不能在状态树中存在两次(mobx-state-tree)
A node cannot exists twice in the state tree ( mobx-state-tree )
在以下模型中通过 setSelectedItem
操作为 selectedItem
赋值时,我收到一条错误消息,显示 Error: [mobx-state-tree] A node cannot exists twice in the state tree. Failed to add SearchModel@/results/0 to path '/selectedItem'
。我检查了文档,但不确定是什么导致了这个问题。
感谢任何帮助。谢谢!
const SearchModel = types
.model({
results: types.array(ItemModel, []),
selectedItem:types.maybeNull(ItemModel,{ id: 0 })
})
.actions(self => ({
setSelectedItem(selItem) {
console.log( 'typeof(selItem)', typeof(selItem));
self.selectedItem=selItem;
}
}));
export default SearchModel;
对于将来寻找此类错误解决方案的任何人,我使用展开运算符将 selItem
的浅表副本分配给 self.selectedItem
,问题就消失了。
代码必须如下所示:
const SearchModel = types
.model({
results: types.array(ItemModel, []),
selectedItem:types.maybeNull(ItemModel,{ id: 0 })
})
.actions(self => ({
setSelectedItem(selItem) {
self.selectedItem = { ...selItem };
}
}));
export default SearchModel;
另一种解决方案是使用 Lodash 库中的 _.deepCopy。它比扩展运算符更通用,因为它会递归地沿着整棵树而不是一层向下移动。这对于较大的树很有用,因此您不必双倍、三倍或四倍传播,并且有 hard-to-read 代码。
这就是您在简单的 mobx-state-tree 商店中使用它的方式。它非常优雅,易于使用。
注意:这是一个递归 pass-by-copy 函数,因此如果对象太大,性能可能会很差。
import _ from 'lodash';
import { types, getRoot, destroy, flow } from "mobx-state-tree";
const SearchModel = types
.model({
results: types.array(ItemModel, []),
selectedItem:types.maybeNull(ItemModel,{ id: 0 })
})
.actions(self => ({
setSelectedItem(selItem) {
self.selectedItem = _.deepCopy(selItem);
}
}));
export default SearchModel;
一个更好的可能性:使用 mobx-state-tree applySnapshot 函数。这应该会自动协调数据结构,并保留 back/forth 能力,因此您可以利用 undo/redo 作为您的状态树。
import { types, getRoot, destroy, flow, applySnapshot } from "mobx-state-tree";
const SearchModel = types
.model({
results: types.array(ItemModel, []),
selectedItem:types.maybeNull(ItemModel,{ id: 0 })
})
.actions(self => ({
setSelectedItem(selItem) {
applySnapshot(self.selectedItem, selItem);
}
}));
export default SearchModel;
在我的例子中,我在第 2 层有一个嵌套对象 "address",所以我也需要为它指定修复:
setSelectedItem(selItem) {
let item = { ...selItem };
item.address = { ...selItem.address }
self.selectedItem = item;
}
我在 React TypeScript 以及 MST 商店中也遇到了同样的问题 非常嵌套且复杂,因此使用展开运算符或 applySnapshot 无效。通过使用 lodash 简单地解决了这个问题。
步骤:
安装: npm i lodash.clonedeep
进口: import cloneDeep from 'lodash/cloneDeep'
使用它(在我的例子中): self.filteredCashGamesList.cashGameTableView = cloneDeep(self.cashGameTableView)
在以下模型中通过 setSelectedItem
操作为 selectedItem
赋值时,我收到一条错误消息,显示 Error: [mobx-state-tree] A node cannot exists twice in the state tree. Failed to add SearchModel@/results/0 to path '/selectedItem'
。我检查了文档,但不确定是什么导致了这个问题。
感谢任何帮助。谢谢!
const SearchModel = types
.model({
results: types.array(ItemModel, []),
selectedItem:types.maybeNull(ItemModel,{ id: 0 })
})
.actions(self => ({
setSelectedItem(selItem) {
console.log( 'typeof(selItem)', typeof(selItem));
self.selectedItem=selItem;
}
}));
export default SearchModel;
对于将来寻找此类错误解决方案的任何人,我使用展开运算符将 selItem
的浅表副本分配给 self.selectedItem
,问题就消失了。
代码必须如下所示:
const SearchModel = types
.model({
results: types.array(ItemModel, []),
selectedItem:types.maybeNull(ItemModel,{ id: 0 })
})
.actions(self => ({
setSelectedItem(selItem) {
self.selectedItem = { ...selItem };
}
}));
export default SearchModel;
另一种解决方案是使用 Lodash 库中的 _.deepCopy。它比扩展运算符更通用,因为它会递归地沿着整棵树而不是一层向下移动。这对于较大的树很有用,因此您不必双倍、三倍或四倍传播,并且有 hard-to-read 代码。
这就是您在简单的 mobx-state-tree 商店中使用它的方式。它非常优雅,易于使用。
注意:这是一个递归 pass-by-copy 函数,因此如果对象太大,性能可能会很差。
import _ from 'lodash';
import { types, getRoot, destroy, flow } from "mobx-state-tree";
const SearchModel = types
.model({
results: types.array(ItemModel, []),
selectedItem:types.maybeNull(ItemModel,{ id: 0 })
})
.actions(self => ({
setSelectedItem(selItem) {
self.selectedItem = _.deepCopy(selItem);
}
}));
export default SearchModel;
一个更好的可能性:使用 mobx-state-tree applySnapshot 函数。这应该会自动协调数据结构,并保留 back/forth 能力,因此您可以利用 undo/redo 作为您的状态树。
import { types, getRoot, destroy, flow, applySnapshot } from "mobx-state-tree";
const SearchModel = types
.model({
results: types.array(ItemModel, []),
selectedItem:types.maybeNull(ItemModel,{ id: 0 })
})
.actions(self => ({
setSelectedItem(selItem) {
applySnapshot(self.selectedItem, selItem);
}
}));
export default SearchModel;
在我的例子中,我在第 2 层有一个嵌套对象 "address",所以我也需要为它指定修复:
setSelectedItem(selItem) {
let item = { ...selItem };
item.address = { ...selItem.address }
self.selectedItem = item;
}
我在 React TypeScript 以及 MST 商店中也遇到了同样的问题 非常嵌套且复杂,因此使用展开运算符或 applySnapshot 无效。通过使用 lodash 简单地解决了这个问题。
步骤:
安装: npm i lodash.clonedeep
进口: import cloneDeep from 'lodash/cloneDeep'
使用它(在我的例子中): self.filteredCashGamesList.cashGameTableView = cloneDeep(self.cashGameTableView)