一个节点不能在状态树(mobx-state-tree)中存在两次

时间:2019-03-24 20:57:48

标签: reactjs mobx mobx-react mobx-state-tree

在以下模型中,通过Error: [mobx-state-tree] A node cannot exists twice in the state tree. Failed to add SearchModel@/results/0 to path '/selectedItem'动作将值分配给selectedItem时,出现错误消息setSelectedItem。我已经检查了文档,但不确定是什么引起了此问题。

感谢任何帮助。谢谢!

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;

5 个答案:

答案 0 :(得分:1)

对于以后寻求解决此类错误的任何人,我使用了散布运算符将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;

答案 1 :(得分:1)

另一种解决方案是使用Lodash库中的_.deepCopy。它比散布运算符更具通用性,因为它将递归遍历整棵树,而不是一棵树。这对于较大的树很有用,因此您不必传播两倍或三倍或四倍的传播,并且代码难以阅读。

这就是您如何在简单的mobx-state-tree存储中使用它的方法。它非常优雅,易于使用。

请注意:这是递归复制传递功能,因此如果对象太大,性能可能会很差。

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;

答案 2 :(得分:0)

一种更好的可能性:使用mobx-state-tree applySnapshot函数。这样可以自动协调数据结构,并保留前进/后退功能,因此您可以在状态树中使用撤消/重做功能。

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;

答案 3 :(得分:0)

在我的情况下,我在级别2上有一个嵌套对象“地址”,因此我还需要为其指定修复程序:

setSelectedItem(selItem) {
  let item = { ...selItem };
  item.address = { ...selItem.address }
  self.selectedItem = item;
}

答案 4 :(得分:0)

我在我们的 React TypeScript 中也遇到了同样的问题,而且我们的 MST 存储 非常嵌套并且复杂,因此使用扩展运算符或 applySnapshot 不起作用。通过使用 lodash 简单地解决了这个问题。

步骤:

安装: npm i lodash.clonedeep

导入: import cloneDeep from 'lodash/cloneDeep'

使用它(就我而言): self.filteredCashGamesList.cashGameTableView = cloneDeep(self.cashGameTableView)