MobX now supports standard decorators! (And what else is next?)
Unfamiliar with MobX? Check out the gist of MobX! This blog post covers classes and decorators specifically, which is just one of the many ways of using MobX.
We're happy to announced that we just released a new minor version of MobX (6.11), which adds support for standard decorators.
Decorators are currently a TC-39 stage 3 proposal, supported both by Babel and TypeScript with minimal setup.
Here is a quick example, taken from the MobX cheat sheet, to show what using decorators looks like with the new standard (yes; no makeObservable
calls anymore!):
import { observable, computed, action, flow } from "mobx"
class Doubler {
@observable accessor value
constructor(value) {
this.value = value
}
@computed
get double() {
return this.value * 2
}
@action
increment() {
this.value++
}
@flow
*fetch() {
const response = yield fetch("/api/value")
this.value = response.json()
}
}
A short history of decorators and MobX
Decorators are popular in many frameworks like Angular, Lit and Nest. MobX has supported decorators since day 1. However, the old implementation was based on the legacy decorators implementation, which was primarily introduced by TypeScript but never supported by the TC-39 committee. The decorators working group, tirelessly led by Kristen Garrett, Daniel Ehrenberg, Yehuda Katz, Ron Buckton and others has been progressing towards a better decorator proposal. This proposal is now at stage 3 and is likely to land. From MobX's side, we have been actively engaging with the working group to make sure that the MobX use case is part of the design.
Given the expected upcoming changes between legacy and standard decorators, when introducing MobX 6.0.0 over 3 years ago, we moved away from promoting decorators by default.
Instead, we provided an alternative (albeit more cumbersome) makeObservable
/ makeAutoObservable
APIs.
This was to make sure that we would be ready to migrate to standard decorators once they were stable enough.
That time has arrived!
Legacy decorators are still supported as well, so either compiler configuration will work. However we will stop supporting legacy decorators in MobX 7. From our benchmarks, standard decorators incur 30% less runtime overhead, so we strongly recommend upgrading.
The difference in performance primarily stems from the stable class shape, which is guaranteed by the new decorators proposal, which was one of the design goals.
One side effect of the new standard is that the @observable
decorator can only be used on accessor
fields (which generate a getter / setter pair behind the scenes).
The standard decorators implementation for MobX was largely written by @Matchlighter, already back in February (the delay in releasing this awesome work is all purely yours truly's fault). So a really big shout out and thanks for all the work that went into this!
Migrating to standard decorators
If you are not using classes to store state with MobX, don't bother at all. But otherwise, in order to migrate to standard decorators, follow these steps:
-
Update your compiler configuration.
-
In TypeScript, standard decorators will work in principle out of the box. Just make sure:
- To upgrade to TypeScript to version 5 or higher
- Make sure the compiler targets
"ES2015"
or higher - Disable or remove the
experimentalDecorators
flag
-
For Babel, support is provided through the
proposal-decorators
plugin.- Make sure to specify version
"2023-05"
or higher - Make sure any legacy decorator config is removed
- Make sure to specify version
- More details can be found on http://mobx.js.org/enabling-decorators.html
-
-
If you were already using legacy decorators:
- Remove all calls to
makeObservable(this)
(that have no second argument). - Replace all invocations of
@observable
with@observable accessor
. Do the same for@observable.ref
and@observable.shallow
.
- Remove all calls to
-
If you were not using decorators already:
- First of all, if you are using
makeObservable(this, annotations)
/makeAutoObservable(this)
, there is no need to migrate to the new decorator setup!. This API will remain supported. Only do so if your team feels this is an improvement and worthwhile. For example for the co-location of the field declaration and observability specifier. - At the moment of writing no codemod is yet available to convert
make(Auto)Observable
calls automatically into decorators. We recommend manually migrating those. - If someone wants to contribute a codemod, feel free to take the
mobx-undecorate
codemod as a starting point.
- First of all, if you are using
The MobX cheat sheet has been updated as well to reflect the latest changes.
What else is next for Mobx?
In the short term, now that standard decorators support has landed, we can start working towards a leaner MobX, in which we can remove already deprecated APIs, legacy decorator support, and possibly some seldomly used features that have been accrued over time.
When we look at the farther horizon, interesting things are currently happening in JavaScript around signals. Signals are hotter than ever, popularized by libraries like Solid and recently Svelte Runes (and many more). As many of you have already realised, MobX has been providing this reactivity model already since 2015 (called Atoms in the MobX source code). Branding MobX as “Signals for React” wouldn't be far off the mark.
MobX provides some fairly unique abstractions on top of signals: A rich, mutable object model that is compatible with idiomatic JavaScript mutability APIs and allows to freely and deeply compose objects, classes, maps, arrays etc. - without additional hassle. We expect that other signal libraries will follow a similar object model in the near future, if they don't already.
However, there is another cool thing happening in this area; there are some explorations to find out whether signals can be standardized. If this becomes reality, it will make MobX leaner. But more interestingly, it will make the object model and reactivity utilities compatible with other frameworks that support the standard. It’s too early to draw any conclusions, but rest assured that MobX will be actively providing input to the working group, like we did for decorators. (This work is not yet public, to simplify some initial validation with existing frameworks, but it will be).
Thanks for all the support and believing in this state management model throughout the years.
The future of reactivity is bright!
Michel Weststrate