xaviergonz / mobx-keystone

A MobX powered state management solution based on data trees with first class support for Typescript, support for snapshots, patches and much more
https://mobx-keystone.js.org
MIT License
551 stars 25 forks source link

Serializing Computed Values with `onSnapshot`/`onPatches`: Valid Mobx-Keystone Use-Case? #442

Open graphographer opened 2 years ago

graphographer commented 2 years ago

Say I have a model Guests with an array of model Guest. Then I have a computed value which is some subset of the array.

@model('Guests')
class Guests extends Model({array: prop<Guest[]>(() => []) {
  @computed
  get someGuests() {
    return this.array.filter(...);
  }
}

Is it within the intended paradigm of Mobx Keystone to wish to serialize this computed array of models using onSnapshot or onPatches?

Currently, I am doing this by setting up a reaction in onAttachedToRootStore in order to track the computed and update a model prop. However, this "violates" a cardinal MobX best practice, which is to avoid/never update observables from reactions.

@model('Guests')
class Guests extends Model({
  array: prop<Guest[]>(() => []),
  ids: prop<string[]>(() => []).withSetter()
}) {
  @computed
  get someGuests() {
    return this.array.filter(...);
  }
  onAttachedToRootStore() {
    const idsDisposer = autorun(() => {
        this.setIds(this.someGuests.map(guest => guest.id));
    });

    return () => {
        idsDisposer();
    };
  }
}

Is this simply not a valid use of MobX Keystone? How might I think about my models differently in order to adapt to my use-case, which is to (reactively) send an array of Guest.ids to the back end?

I understand that one way of thinking about this is that the local tree can be re-created elsewhere by essentially running the same computed with the total state of the local tree. However, in my case, the computation is more efficiently done on the client, and the results sent to the server.

xaviergonz commented 2 years ago

do you need ids to be a mobx keystone property? perhaps it could be a plain variable if that feels less "impure"

graphographer commented 2 years ago

By "plain variable" do you mean if it was a normal, observable property on the class?

One thing I'm trying to wrap my head around with using Mobx Keystone is whether an entity without the need for serializable state should or should not be a Keystone Model.

xaviergonz commented 2 years ago

Yes, that's what I mean.

As for if it should be a mobx keystone model or not, depends. Do you need serialization or a middleware (such as undo/redo)? Then yes, else up to you.

Basically, your document and/or config could be part of mobx-keystone, while everything else (e.g. UI state) could be in plain mobx classes or the react state.

graphographer commented 2 years ago

Ah! Thank you for that description, I find it very helpful. So, for example, even if I don't require something to be serializable, the middleware patterns can be useful even for plain observables.

I'll still have to do some thinking, however, about the clearest way to serialize a computed to send to the server. I was just hoping there was a "native" keystone pattern already.