mobxmobx-state-tree

Sharing actions between models in mobx-state-tree


I would like to ask you if there's any way of sharing actions between models in mobx-state-tree?

Let's consider this example (login action of AuthModel):

import { types } from "mobx-state-tree";

const UIModel = types
  .model({
    globalLoading: types.boolean,
  })
  .actions((self) => ({
    setGlobalLoading(value) {
      self.globalLoading = value;
    },
  }));

const AuthModel = types
  .model({
    userData: types.maybeNull(types.User),
  })
  .actions((self) => ({
    login() {
      // call UIModel.setGlobalLoading(true) somehow
    },
  }));

const RootModel = types.model({
  ui: UIModel,
  auth: AuthModel,
});

RootModel.create({
  auth: {
    userData: null
  },
  ui: {
    globalLoading: false
  }
})

Is there any way to somehow "inject" reference to UIModel inside AuthModel? I can't find anything like this in docs or examples I've seen online.


Solution

  • Yes, you can reference the UIModel from inside AuthModel using the getRoot function.

    This returns the root object of your tree, in this case, RootModel.

    So, if your UIModel is:

    const UIModel = types
      .model({
        globalLoading: types.boolean,
      })
      .actions((self) => ({
        setGlobalLoading(value) {
          self.globalLoading = value;
        },
      }));
    

    And this is your RootModel:

    const RootModel = types.model({
      ui: UIModel,
      auth: AuthModel,
    });
    
    RootModel.create({
      auth: {
        userData: null
      },
      ui: {
        globalLoading: false
      }
    })
    

    Then you can reference UIModel inside AuthModel like this:

    const AuthModel = types
      .model({
        userData: types.maybeNull(types.User),
      })
      .actions((self) => ({
        login() {
           const {ui} = getRoot(self)
           ui.setGlobalLoading(true)
        },
      }));
    

    That gives you access to the actions and data in all sub-trees (your models) via the root tree.