4

I want to use mobx without using decorators. Usually I use decorate from mobx package but in this particular case, I could not find a way to make it work.

Original code :

import { observable } from 'mobx'
import { create, persist } from 'mobx-persist'

class Order {
  @persist('object')
  @observable
  currentOrder = null
}

What I tried :

import { observable, decorate } from 'mobx'
import { create, persist } from 'mobx-persist'
import { compose } from 'recompose'

class Order {
  currentOrder = null
}

decorate(Order, {
    currentOrder: compose(persist('object'), observable),
})

The error comes from persist telling serializr decorator is not used properly. Any idea why this is different from above and does not work ?

Harijoe
  • 1,771
  • 1
  • 16
  • 27

2 Answers2

2

TL;DR

Property Decorators requires a very specific composition implementation.

Solution Demo:
Edit MobX Decorators Composer

Full Answer

Property Decorators are basically a function of the form:
(target, prop, descriptor) => modifiedDescriptor

So, in order to compose two Property Decorators you need to pass the 1st decorator's result as a third argument of the 2nd decorator (along with target and prop).

Recompose.compose (same as lodash.flowRight) applies functions from right to left and passing the result as a single argument to the next function.

Thus, you can't use Recompose.compose for composing decorators, but you can easily create a composer for decorators:

/* compose.js */

export default (...decorators) => (target, key, descriptor) =>
  decorators.reduce(
    (accDescriptor, decorator) => decorator(target, key, accDescriptor),
    descriptor
  );

Then we use it in order to compose observable and persist("object").

/* Order.js */

import { observable, decorate, action } from "mobx";
import { persist } from "mobx-persist";
import compose from "./compose";

class Order {
  currentOrder = null;
}

export default decorate(Order, {
  currentOrder: compose(
    observable,
    persist("object")
  )
});

[21/8/18] Update for MobX >=4.3.2 & >=5.0.4:

I opened PRs (which have been merged) for MobX5 & MobX4 in order to support multiple decorators OOB within the decorate utility function.
So, this is available in MobX >=4.3.2 & >= 5.0.4:

import { decorate, observable } from 'mobx'
import { serializable, primitive } from 'serializr'
import persist from 'mobx-persist';

class Todo {
    id = Math.random();
    title = "";
    finished = false;
}
decorate(Todo, {
    title: [serializable(primitive), persist('object'), observable],
    finished: observable
})
Ramy Ben Aroya
  • 2,333
  • 14
  • 20
0

An easier solution is to have

class Stuff {
   title = ''
   object = {
      key: value
   }
}

decorate(Todo, {
    title: [persist, observable],
    object: [persist('object'),observable]
})

No need to install the serializr package. The above functionality is built into mobx persist.

total-N00b
  • 45
  • 1
  • 5