docs/migrating-from-4-or-5.md
MobX 6 is quite different from MobX 5. This pages covers a migration guide from MobX 4 and 5 to 6, and an extensive list of all the changes.
For a better understanding, check out the MobX 6.0 CHANGELOG.
⚠️ Warning: Depending on factors like the size and complexity of your code base, your MobX usage patterns, and the quality of your automated tests, this migration guide might take you anywhere between an hour and a couple of days. Please refrain from upgrading if you don't trust your Continuous Integration or QA / test procedures enough to pick up any unexpected breakages. Unexpected behavioral changes might be caused by changes in MobX itself or the changes needed to your Babel / TypeScript build configuration. ⚠️
mobx to the latest version of MobX 4/5 and solve any deprecation messages.mobx to version 6.import { configure } from "mobx"; configure({ useProxies: "never" }) at the initialization of your application, to back-out of the Proxy implementation. Check out the Proxy Support section for more details.["@babel/plugin-proposal-class-properties", { "loose": false }]plugin-proposal-decorators from your babel configuration and dependencies. Check out the Enabling decorators {🚀} section for more details."useDefineForClassFields": true to your compiler config.experimentalDecorators configuration from your TypeScript config. Check out the Enabling decorators {🚀} section for more details.import {configure} from "mobx"; configure({ enforceActions: "never" });. After finishing the entire migration process and validating that your project works as expected, consider enabling the flags computedRequiresReaction, reactionRequiresObservable and observableRequiresReaction and enforceActions: "observed" to write more idiomatic MobX code.makeObservableDue to standardized JavaScript limitations in how class fields are constructed, it is no longer possible for MobX to alter the behavior of class fields by means of decorators or the decorate utility. Instead, fields have to be made observable by the constructor. This can be done in three different ways:
makeObservable in the constructor and explicitly define which field should be made observable using which decorator. For example: makeObservable(this, { count: observable, tick: action, elapsedTime: computed }) (note that the second argument corresponds to what would be passed to decorate). This is the recommended approach if you want to drop decorators in your code base, and the project isn't yet too big.makeObservable(this) in the constructor. This will pick up the metadata generated by the decorators. This is the recommended way if you want to limit the impact of a MobX 6 migration.makeAutoObservable(this) in the class constructor's.Check out makeObservable / makeAutoObservable for more details.
Some specifics to note:
makeObservable / makeAutoObservable needs to be done in every class definition that declares MobX based members. So if a sub-class and super-class both introduce observable members, they will both have to call makeObservable.makeAutoObservable will mark methods using a new decorator autoAction, that will apply action only if it is not in a derivation context. This makes it safe to call automatically decorated methods also from computed properties.Migrating a large code base with lots of classes might be daunting. But no worries, there is a code-mod available that will automate the above process!!
mobx-undecorate codemodIf you are an existing MobX user you have code that uses a lot of decorators, or the equivalent calls to decorate.
The mobx-undecorate package provides a codemod that can automatically update your code to be conformant to MobX 6. There is no need to install it; instead you download and execute it using the npx tool which you do need to install if you haven't already.
To get rid of all uses of MobX decorators and replace them with the equivalent makeObservable calls, go to the directory that contains your source code and run:
npx mobx-undecorate
MobX will continue to support decorators -- so if you want to retain them
and only introduce makeObservable(this) where required, you can use the --keepDecorators option:
npx mobx-undecorate --keepDecorators
See documentation for more options.
mobx-undecorateThe mobx-undecorate command has to introduce a constructor in classes that do not yet have one. If base class of the constructor expects arguments, the codemod cannot introduce these arguments for the subclass being upgraded, and the super call won't pass them either. You have to fix these manually.
The tool will generate a // TODO: [mobx-undecorate] comment in these cases.
We do have a special case for React class components to do the right thing and
pass along props to the superclass.
Functions that become part of a deep observable structure are automatically converted to autoAction or to flow if it's a generator function. See inference rules for details.
This means that the original function reference is not preserved - in the same spirit as the original array/object/set/map reference is lost when converted to observable. This can be surprising in some situations.
If this behavior is not desired use observable.shallow / observable.ref / false / deep: false to prevent the conversion process or make sure the function is already an action as shown in the issue.