Mimoid
Mimoid

Reputation: 812

How to run reaction callback on every possible change in MobX?

This is my simplified store:

export class ProfileStore {
  profile = {
    id: 1,
    name: "Tommy",
    todos: [
      {
        value: "Clean the room",
        done: false
      }
    ]
  };

  constructor() {
    makeObservable(this, {
      profile: observable,
    });
  }
}

My goal is to listen to every possible change inside "profile" observable. I wanted to use reaction from MobX for this but it is kinda tricky.

reaction(
      () => this.profile,
      () => {
        console.log("change");
      }
    );

Above example doesn't work at all because MobX doesn't react to values but to properties and references. So I changed it to this:

reaction(
      () => ({
        id: this.profile.id,
        name: this.profile.name,
        todos: this.profile.todos.slice()
      }),
      () => {
        console.log("change");
      }
    );

And it started working but not entirely. It listened to every change besides toggling done property in todos. And if I add another property I would need to list in here which is kinda tedious.

What's the best way to handle this problem? How to react to every possible change?

I made a codesandbox for this: link

Try to press buttons and look at the counter.

Upvotes: 2

Views: 1333

Answers (1)

Danila
Danila

Reputation: 18516

To react for every possible change you need to dereference every property. To do that, for example, you can use toJS method to serialize your profile object. (Or even native JSON.stringify):

import { reaction, toJS } from 'mobx';

// ...

    reaction(
      () => toJS(profileStore.profile),
      () => {
        setReactionCounter((state) => state + 1);
      }
    );

Codesandbox

Upvotes: 5

Related Questions