mobx-state-tree icon indicating copy to clipboard operation
mobx-state-tree copied to clipboard

Duplicate node inside same tree

Open SandroMaglione opened this issue 4 years ago • 3 comments

Question

  • [x] I've checked documentation and searched for existing issues
  • [x] I tried the spectrum channel

I am trying to add a copy of a node to the same tree. I have a function that takes a list, an index, and a new value and inserts the given value at the given index in the list. For example (with numbers):

addAtIndex([1, 2, 3], 1, 10) // => [1, 10, 2, 3]

I use this function to add a copy of a node with a new id to a list in the tree, like so (taken from here):

addAtIndex(
  sourceList,
  index,
  ElementType.create(
    {
      ...elementToCopy,
      id: uuid(),
    },
    getEnv(elementToCopy)
  )
)

The problem is that ElementType is composed of other complex types and I have this error:

Error: [mobx-state-tree] Cannot add an object to a state tree if it is already part of the same or another state tree.

This happens because some attributes inside elementToCopy have the same reference. In fact, doing like below works but the two nodes have the same reference and same id, which is not what I am trying to achieve:

addAtIndex(
  sourceList,
  index,
  clone(elementToCopy),
)

Am I doing something wrong? How can I duplicate a node in a tree while also changing its identifier?

SandroMaglione avatar Jan 27 '21 19:01 SandroMaglione

Can you use getSnapshot on the element that you wish to copy, and then change the id and use the snapshot data to create a new element?

Balderscape avatar Jan 31 '21 11:01 Balderscape

I tried the solution below but I get the same error (I cannot use getSnapshot because elementToCopy is already a SnapshotOut):

addAtIndex(
  sourceList,
  index,
  {
    ...elementToCopy,
    id: 'newid',
  }
)

The problem actually is not creating a new elementToCopy like this, but that elementToCopy's definition contains other types.model that, with this implementation, maintain the same reference and cause the error.

Here below a (simplified) example of the model definition:

const ElementToCopy = types
  .model({
    id: types.identifier,
    // Nested types.model
    child: types.union(
      types.model({
        id: types.identifier,
        name: types.literal('NAME1'),
      }),
      types.model({
        id: types.identifier,
        name: types.literal('NAME2'),
      }),
      types.model({
        id: types.identifier,
        name: types.literal('NAME3'),
      })
    ),
  });

The error reports that the reference to child is is already part of the same or another state tree. Therefore it changes the reference of elementToCopy, but not the reference to child.

Any idea on how to solve the problem?

SandroMaglione avatar Jan 31 '21 17:01 SandroMaglione

This is an old issue, but I thought I might drop in a link to mst-reference-pool, which can help with this type of issue.

jamonholmgren avatar Aug 17 '22 20:08 jamonholmgren

Hey folks, I think the Infinite Red library is a good tool to help out with this exact issue.

If y'all want to keep discussing the underlying problem, I've converted a similar issue into a discussion thread here: https://github.com/mobxjs/mobx-state-tree/discussions/2035, and would love to have additional input.

For now, I'm going to close out this issue.

coolsoftwaretyler avatar Jun 28 '23 03:06 coolsoftwaretyler