Mobx-state-tree: Is there a way to reset a model to its initial state?

Created on 2 May 2018  路  10Comments  路  Source: mobxjs/mobx-state-tree

Right now when I need to reset a model (for example when I navigate with the app router to a certain page), I have a reset action like this:

reset() {
  self.name = ''
  self.owner = ''
  self.location = ''
  self.employees = 0
  self.isOpen = false
  self.list = []
},

These values are the same I pass as a second argument to the t.optional in the model, like this:

const SampleModel = t
  .model('SampleModel', {
    name: t.optional(t.string, ''),
    owner: t.optional(t.string, ''),
    location: t.optional(t.string, ''),
    employees: t.optional(t.number, 0),
    isOpen: t.optional(t.boolean, false),
    list: t.optional(t.array(t.string), []),
  })

and this is how I initialize that state:

const State = t
  .model('State', {
    sampleModel: t.optional(SampleModel, {}),
    otherSubState: t.optional(OtherSubState, {}),
  })

Is there a standard and easier way to reset a model to its initial state?

Most helpful comment

Maybe you can save it on afterCreate. Something like this:

const State = t
  .model('State', {
    sampleModel: t.optional(SampleModel, {}),
    otherSubState: t.optional(OtherSubState, {}),
  })
  .actions(self => {
    let initialState = {};
    return {
      afterCreate: () => {
        initialState = getSnapshot(self);
      },
      reset: () => {
        applySnapshot(self, initialState);
      },
    }
  })

All 10 comments

Maybe you can save it on afterCreate. Something like this:

const State = t
  .model('State', {
    sampleModel: t.optional(SampleModel, {}),
    otherSubState: t.optional(OtherSubState, {}),
  })
  .actions(self => {
    let initialState = {};
    return {
      afterCreate: () => {
        initialState = getSnapshot(self);
      },
      reset: () => {
        applySnapshot(self, initialState);
      },
    }
  })

I used the method mentioned above getting and saving snapshot on the initial state. It works great most of them time! However, when the model is big, entire UI locks waiting for, I'm guessing, garbage collection to finish?

Do you have any other recommendation for reinitializing? Thank you!

Here is what I ended up doing:

const State = t
  .model('State', {
    sampleModel: t.optional(SampleModel, {}),
    otherSubState: t.optional(OtherSubState, {}),
  })
  .actions(self => ({
    resetSubState(subState) {
      const subStateName = subState.$treenode.subpath
      self[subStateName] = {}
    },
  }))

And this is what become of the reset method

reset() {
  const { resetSubState } = getRoot(self)
  resetSubState(self)
},

A bit hacky, but this is what I needed to do.

And making a snapshot afterCreate() does not work in react-native if you restart the app. As a new afterCreate() will be triggered uppon app restore with the wrong snapshot.

UPDATE: here is a better way to do it

const State = t
  .model('State', {
    sampleModel: t.optional(SampleModel, {}),
    otherSubState: t.optional(OtherSubState, {}),
  })
  .actions(self => ({
    reset() {
      Object.keys(self).forEach(key => {
        self[key].reset && self[key].reset()
      })
    },
  }))

reset method:

reset() {
  applySnapshot(self, {})
},

No need to save the snapshot an afterCreate, assuming you always use the default values.

Yes that's a nice example, thanks @marcofugaro. And you could even compose this reset method with your stores ;)

@marcofugaro so to reset model I just need to call applySnapshot(self, {})?
why do you iterate over submodels and call reseton them?

that works too @danikkks!

In my case I had some states that couldn't be reset (like mst-react-router). So I was checking if they had the reset method.

ok, I got it, thanks!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

A-gambit picture A-gambit  路  3Comments

lishine picture lishine  路  4Comments

elado picture elado  路  4Comments

FredyC picture FredyC  路  3Comments

ShootingStarr picture ShootingStarr  路  4Comments