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

Using detach with an array, it cannot be reattached to the tree

Open evelant opened this issue 4 years ago • 0 comments

Bug report

  • [ X ] I've checked documentation and searched for existing issues
  • [ X ] I've made sure my project is based on the latest MST version
  • [ X ] Fork this code sandbox or another minimal reproduction.

Sandbox link or minimal reproduction code https://codesandbox.io/s/cool-lake-w7co5?file=/src/App.tsx

Describe the expected behavior const detachedArray = detach(self.myArray); self.someOtherArray = cast(detachedArray); should detach myArray and its contents then reattach it at someOtherArray.

Describe the observed behavior [mobx-state-tree] Cannot add an object to a state tree if it is already part of the same or another state tree. Tried to assign an object to '/drawPile/0', but it lives already at '/3'

It appears that the contents of the array are not marked as detached properly.

I'm modeling a card game where I want to shuffle the "discard pile" and replace the "draw pile" with the shuffled cards. If I do it as above by detaching the array MST throws the "already lives" error. To work around this I must individually detach each element of an array instead of detaching the whole array.

See this codesandbox: https://codesandbox.io/s/cool-lake-w7co5?file=/src/App.tsx

I expected the reshuffleBad and reshuffleGood actions to be identical, but reshuffleBad throws the above error.

Here's a code snippet from the sandbox

const CardsModel = t
  .model({
    discardPile: t.array(CardModel),
    drawPile: t.array(CardModel)
  })
  .actions((self) => ({
    reshuffleBad() {
      //Crashes!
      const discards = detach(self.discardPile);
      const draws = detach(self.drawPile);
      const shuffled = _.shuffle([...discards, ...draws]);
      self.drawPile = cast(shuffled);
    },
    reshuffleGood() {
      //No problem
      const discards = self.discardPile.map(detach);
      const drawDeck = self.drawPile.map(detach);
      const shuffled = _.shuffle([...discards, ...drawDeck]);
      self.drawPile = cast(shuffled);
    }
  }));

evelant avatar Nov 23 '20 20:11 evelant