从 MobX 4/5 迁移 {🚀}
¥Migrating from MobX 4/5 {🚀}
MobX 6 与 MobX 5 有很大不同。本页涵盖了从 MobX 4 和 5 到 6 的迁移指南,以及所有更改的详细列表。
¥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.
为了更好地理解,请查看 MobX 6.0 CHANGELOG。
¥For a better understanding, check out the MobX 6.0 CHANGELOG.
⚠️ 警告:根据代码库的大小和复杂性、MobX 使用模式以及自动化测试的质量等因素,本迁移指南可能会花费你一小时到几天的时间。如果你不相信你的持续集成或质量保证/测试程序足以发现任何意外的损坏,请不要升级。意外的行为变化可能是由 MobX 本身的变化或 Babel / TypeScript 构建配置所需的变化引起的。⚠️
¥⚠️ 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. ⚠️
入门
¥Getting started
将
mobx
更新到最新版本的 MobX 4/5 并解决任何弃用消息。¥Update
mobx
to the latest version of MobX 4/5 and solve any deprecation messages.将
mobx
更新到版本 6。¥Update
mobx
to version 6.如果你从 MobX 4 升级,并且需要在没有代理的情况下支持 Internet Explorer / React Native,请在应用初始化时调用
import { configure } from "mobx"; configure({ useProxies: "never" })
,以退出代理实现。查看 代理支持 部分了解更多详细信息。¥If you are upgrading from MobX 4, and you will need to support Internet Explorer / React Native without proxies, call
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 用户:
¥For babel users:
如果你使用 Babel 并启用了类属性,请禁用旧的松散字段支持:
["@babel/plugin-proposal-class-properties", { "loose": false }]
¥If you are using Babel and have class-properties enabled, disable the legacy loose field support:
["@babel/plugin-proposal-class-properties", { "loose": false }]
(可选的)在 MobX 6 中,装饰器已成为可选加入。如果你不再希望使用装饰器,请从 babel 配置和依赖中删除
plugin-proposal-decorators
。查看 启用装饰器 {🚀} 部分了解更多详细信息。¥(Optional) In MobX 6 decorators have become opt-in. If you no longer wish to use decorators, remove
plugin-proposal-decorators
from your babel configuration and dependencies. Check out the Enabling decorators {🚀} section for more details.
对于 Typescript 用户:
¥For Typescript users:
将标志
"useDefineForClassFields": true
添加到你的编译器配置中。¥Add the flag
"useDefineForClassFields": true
to your compiler config.(可选的)在 MobX 6 中,装饰器已成为可选加入。如果你不再希望使用装饰器,请从 TypeScript 配置中删除/禁用
experimentalDecorators
配置。查看 启用装饰器 {🚀} 部分了解更多详细信息。¥(Optional) In MobX 6 decorators have become opt-in. If you no longer wish to use decorators, remove / disable the
experimentalDecorators
configuration from your TypeScript config. Check out the Enabling decorators {🚀} section for more details.
MobX 默认配置变得更加严格。我们建议在完成升级后采用新的默认设置,请查看 配置 {🚀} 部分。在迁移过程中,我们建议以与 v4/v5 中相同的方式配置 MobX:
import {configure} from "mobx"; configure({ enforceActions: "never" });
。完成整个迁移过程并验证你的项目是否按预期工作后,请考虑启用标志computedRequiresReaction
、reactionRequiresObservable
以及observableRequiresReaction
和enforceActions: "observed"
以编写更惯用的 MobX 代码。¥The MobX default configuration has become more strict. We recommend to adopt the new defaults after completing the upgrade, check out the Configuration {🚀} section. During migration, we recommend to configure MobX in the same way as it would be in v4/v5 out of the box:
import {configure} from "mobx"; configure({ enforceActions: "never" });
. After finishing the entire migration process and validating that your project works as expected, consider enabling the flagscomputedRequiresReaction
,reactionRequiresObservable
andobservableRequiresReaction
andenforceActions: "observed"
to write more idiomatic MobX code.
makeObservable
升级类以使用 ¥Upgrading classes to use makeObservable
由于标准化 JavaScript 对类字段构造方式的限制,MobX 不再可能通过装饰器或 decorate
实用程序来改变类字段的行为。相反,字段必须可由 constructor
观察。这可以通过三种不同的方式完成:
¥Due 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:
删除所有装饰器并在
constructor
中调用makeObservable
并显式定义应使用哪个装饰器使哪个字段可观察。例如:makeObservable(this, { count: observable, tick: action, elapsedTime: computed })
(请注意,第二个参数对应于传递给decorate
的参数)。如果你想在代码库中删除装饰器,并且项目还不是太大,那么这是推荐的方法。¥Remove all decorators and call
makeObservable
in theconstructor
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 todecorate
). This is the recommended approach if you want to drop decorators in your code base, and the project isn't yet too big.保留所有装饰器并在
constructor
中调用makeObservable(this)
。这将获取装饰器生成的元数据。如果你想限制 MobX 6 迁移的影响,这是推荐的方法。¥Leave all the decorators and call
makeObservable(this)
in theconstructor
. 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.删除装饰器并在类
constructor
中使用makeAutoObservable(this)
。¥Remove decorators and use
makeAutoObservable(this)
in the classconstructor
's.
查看 makeObservable / makeAutoObservable 了解更多详细信息。
¥Check out makeObservable / makeAutoObservable for more details.
一些需要注意的细节:
¥Some specifics to note:
需要在声明基于 MobX 的成员的每个类定义中使用
makeObservable
/makeAutoObservable
。因此,如果子类和超类都引入了可观察成员,则它们都必须调用makeObservable
。¥Using
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 callmakeObservable
.makeAutoObservable
将使用新的装饰器autoAction
标记方法,只有当action
不在派生上下文中时,才会应用action
。这使得从计算属性调用自动修饰方法也变得安全。¥
makeAutoObservable
will mark methods using a new decoratorautoAction
, that will applyaction
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
codemod 升级你的代码
使用 ¥Upgrading your code with the mobx-undecorate
codemod
如果你是现有的 MobX 用户,你的代码使用了大量装饰器,或者对 decorate
的等效调用。
¥If you are an existing MobX user you have code that uses a lot of decorators, or the equivalent calls to decorate
.
mobx-undecorate
包提供了一个 codemod,可以自动更新你的代码以符合 MobX 6。无需安装;相反,你可以使用 npx
工具下载并执行它,如果你尚未安装该工具,则需要安装该工具。
¥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.
要摆脱 MobX 装饰器的所有使用并将其替换为等效的 makeObservable
调用,请转到包含源代码的目录并运行:
¥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 将继续支持装饰器 - 所以如果你想保留它们并且只在需要的地方引入 makeObservable(this)
,你可以使用 --keepDecorators
选项:
¥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-undecorate
的局限性
¥Limitations of mobx-undecorate
mobx-undecorate
命令必须在尚无构造函数的类中引入构造函数。如果构造函数的基类需要参数,则 codemod 无法为要升级的子类引入这些参数,并且 super
调用也不会传递它们。你必须手动修复这些问题。在这些情况下,该工具将生成 // TODO: [mobx-undecorate]
注释。
¥The 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.
我们确实有一个特殊情况,让 React 类组件做正确的事情并将 props
传递给超类。
¥We do have a special case for React class components to do the right thing and
pass along props
to the superclass.
函数自动转换
¥Functions are auto-converted
成为深度可观察结构一部分的函数会自动转换为 autoAction
或 flow
(如果它是生成器函数)。详情请参见 推断规则。这意味着原始函数引用不会被保留 - 本着同样的精神,原始数组/对象/集合/映射引用在转换为可观察时会丢失。在某些情况下这可能会令人惊讶。如果不需要这种行为,请使用 observable.shallow
/ observable.ref
/ false
/ deep: flase
来阻止转换过程或确保该函数已经是 action
,如问题中所示。
¥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: flase
to prevent the conversion process or make sure the function is already an action
as shown in the issue.