Search code examples
reactjsmobxmobx-reactmobx-state-tree

Mobx-state-tree use mobx reactions inside the tree - Good or Bad practice?


I have an article which is a mobx-state-tree object and I am using it in a react application.

This is an action inside my tree

setId(id: string) {
  self.id = id

  this.updateProduct()
},

And the event

 <input
  value={comp.productId}
  onChange={(e) => comp.setId(e.target.value)}
/>

The problem is that this.updateProduct() runs on every change and makes an async call after each key press.

I would like to take advantage of the mobx reactions and use something like

reaction(
() => ({
  id: this.id
}),
() => {
  this.updateProduct()
}, {
  delay: 500 // this is the key thing
})

I've found delay to be pretty useful in such cases so I would like to use them inside the tree.

Is it a good practice to add reactions inside the mobx-state-tree? If yes, where is the correct place to use the reactions?

I can define the reaction inside the react component but them it will be outside of the tree. Is it a good practice to be outside of the tree?


Solution

  • You can use the afterCreate and beforeDestroy actions to create and dispose a reaction.

    Example

    .actions(self => {
      let dispose;
    
      const afterCreate = () => {
        dispose = reaction(
          () => ({
            id: this.id
          }),
          () => {
            this.updateProduct();
          },
          {
            delay: 500
          }
        );
      };
    
      const beforeDestroy = dispose;
    
      return {
        afterCreate,
        beforeDestroy
      };
    });
    

    You can also use the addDisposer helper so there is no need for manual cleanup in beforeDestroy if you prefer.

    .actions(self => {
      function afterCreate() {
        const dispose = reaction(
          () => ({
            id: this.id
          }),
          () => {
            this.updateProduct();
          },
          {
            delay: 500
          }
        );
    
        addDisposer(self, dispose);
      }
    
      return {
        afterCreate
      };
    });