MobX 中文网

MobX 中文网

  • API 文档
  • Nodejs.cn 旗下网站

›微调

介绍

  • 关于 MobX
  • 关于本文档
  • 安装
  • MobX 的要点

MobX 核心

  • 可观察状态
  • 操作
  • 计算
  • 反应 {🚀}
  • API

MobX 与 React

  • React 集成
  • React 优化 {🚀}

提示与技巧

  • 定义数据存储
  • 了解反应性
  • 子类化
  • 分析反应性 {🚀}
  • 使用参数进行计算 {🚀}
  • MobX-utils {🚀}
  • 自定义可观察值 {🚀}
  • 惰性可观察量 {🚀}
  • 集合实用程序 {🚀}
  • 拦截和观察 {🚀}

微调

  • 配置 {🚀}
  • 装饰器 {🚀}
  • 从 MobX 4/5 迁移 {🚀}

装饰器

¥Decorators

启用装饰器

¥Enabling decorators

经过多年的修改,ES 装饰器终于达到了 TC39 流程的第 3 阶段,这意味着它们相当稳定,不会像之前的装饰器提案那样再次经历重大变化。MobX 已经实现了对这种新的 "2022.3/第 3 阶段" 装饰器语法的支持。使用现代装饰器,不再需要调用 makeObservable / makeAutoObservable。

¥After years of alterations, ES decorators have finally reached Stage 3 in the TC39 process, meaning that they are quite stable and won't undergo breaking changes again like the previous decorator proposals have. MobX has implemented support for this new "2022.3/Stage 3" decorator syntax. With modern decorators, it is no longer needed to call makeObservable / makeAutoObservable.

2022.3 装饰器受以下支持:

¥2022.3 Decorators are supported in:

  • TypeScript(5.0 及更高版本,确保未启用 experimentalDecorators 标志)。示例提交。

    ¥TypeScript (5.0 and higher, make sure that the experimentalDecorators flag is NOT enabled). Example commit.

  • 对于 Babel,请确保插件 proposal-decorators 已启用最高版本(当前为 2023-05)。示例提交。

    ¥For Babel make sure the plugin proposal-decorators is enabled with the highest version (currently 2023-05). Example commit.

// tsconfig.json
{
    "compilerOptions": {
        "experimentalDecorators": false /* or just remove the flag */
    }
}

// babel.config.json (or equivalent)
{
    "plugins": [
        [
            "@babel/plugin-proposal-decorators",
            {
                "version": "2023-05"
            }
        ]
    ]
}
  • Vite 配置

    ¥Vite configuration

// vite.config.js
{
    plugins: [
        react({
            babel: {
                plugins: [
                    [
                        "@babel/plugin-proposal-decorators",
                        {
                            version: "2023-05"
                        }
                    ]
                ]
            }
        })
    ]
}

使用装饰器

¥Using decorators

import { observable, computed, action } from "mobx"

class Todo {
    id = Math.random()
    @observable accessor title = ""
    @observable accessor finished = false

    @action
    toggle() {
        this.finished = !this.finished
    }
}

class TodoList {
    @observable accessor todos = []

    @computed
    get unfinishedTodoCount() {
        return this.todos.filter(todo => !todo.finished).length
    }
}

请注意使用 @observable 时新 accessor 关键字的用法。它是 2022.3 规范的一部分,如果你想使用现代装饰器,则需要它。

¥Notice the usage of the new accessor keyword when using @observable. It is part of the 2022.3 spec and is required if you want to use modern decorators.

Using legacy decorators

我们不建议代码库使用 TypeScript / Babel 旧版装饰器,因为它们永远不会成为该语言的正式部分,但你仍然可以使用它们。它确实需要特定的转译设置:

¥We do not recommend codebases to use TypeScript / Babel legacy decorators since they well never become an official part of the language, but you can still use them. It does require a specific setup for transpilation:

版本 6 之前的 MobX 鼓励使用旧版装饰器并将事物标记为 observable、computed 和 action。虽然 MobX 6 建议不要使用这些装饰器(而是使用现代装饰器或 makeObservable/makeAutoObservable),但在当前的主要版本中仍然是可能的。MobX 7 中将删除对旧版装饰器的支持。

¥MobX before version 6 encouraged the use of legacy decorators and mark things as observable, computed and action. While MobX 6 recommends against using these decorators (and instead use either modern decorators or makeObservable / makeAutoObservable), it is in the current major version still possible. Support for legacy decorators will be removed in MobX 7.

import { makeObservable, observable, computed, action } from "mobx"

class Todo {
    id = Math.random()
    @observable title = ""
    @observable finished = false

    constructor() {
        makeObservable(this)
    }

    @action
    toggle() {
        this.finished = !this.finished
    }
}

class TodoList {
    @observable todos = []

    @computed
    get unfinishedTodoCount() {
        return this.todos.filter(todo => !todo.finished).length
    }

    constructor() {
        makeObservable(this)
    }
}

Migrating from legacy decorators

要从传统装饰器迁移到现代装饰器,请执行以下步骤:

¥To migrate from legacy decorators to modern decorators, perform the following steps:

  1. 从 TypeScript 配置(或 Babel 等效配置)中禁用/删除 experimentalDecorators 标志

    ¥Disable / remove the experimentalDecorators flag from your TypeScript configuration (or Babel equivalent)

  2. 从使用装饰器的类构造函数中删除所有 makeObservable(this) 调用。

    ¥Remove all makeObservable(this) calls from class constructors that use decorators.

  3. 将 @observable(及其变体)的所有实例替换为 @observable accessor

    ¥Replace all instances of @observable (and variations) with @observable accessor

请注意,将 accessor 添加到类属性会将其更改为 get 和 set 类方法。与类属性不同,类方法不可枚举。这可能会给某些 API 带来新的行为,例如 Object.keys、JSON.stringify 等。

¥Please note that adding accessor to a class property will change it into get and set class methods. Unlike class properties, class methods are not enumerable. This may introduce new behavior with some APIs, such as Object.keys, JSON.stringify, etc.

Decorator changes / gotchas

MobX 2022.3 装饰器与 MobX 5 装饰器非常相似,因此用法基本相同,但存在一些问题:

¥MobX' 2022.3 Decorators are very similar to the MobX 5 decorators, so usage is mostly the same, but there are some gotchas:

  • @observable accessor 装饰器是不可枚举的。accessor 在过去没有直接对应词 - 它们是语言中的一个新概念。我们选择使它们成为不可枚举、非拥有的属性,以便更好地遵循 ES 语言的精神和 accessor 的含义。可枚举性的主要案例似乎是围绕序列化和剩余解构。

    ¥@observable accessor decorators are not enumerable. accessors do not have a direct equivalent in the past - they're a new concept in the language. We've chosen to make them non-enumerable, non-own properties in order to better follow the spirit of the ES language and what accessor means. The main cases for enumerability seem to have been around serialization and rest destructuring.

    • 关于序列化,隐式序列化所有属性在 OOP 世界中可能并不理想,因此这似乎不是一个重大问题(考虑实现 toJSON 或使用 serializr 作为可能的替代方案)

      ¥Regarding serialization, implicitly serializing all properties probably isn't ideal in an OOP-world anyway, so this doesn't seem like a substantial issue (consider implementing toJSON or using serializr as possible alternatives)

    • 解决剩余解构问题,这是 MobX 中的反模式 - 这样做会(可能是不必要的)触及所有可观察量并使观察者过度反应)。

      ¥Addressing rest-destructuring, such is an anti-pattern in MobX - doing so would (likely unwantedly) touch all observables and make the observer overly-reactive).

  • @action some_field = () => {} 过去和现在都是有效的用法。但是,旧式装饰器和现代装饰器之间的继承不同。

    ¥@action some_field = () => {} was and is valid usage. However, inheritance is different between legacy decorators and modern decorators.

    • 在旧式装饰器中,如果超类有一个由 @action 修饰的字段,而子类试图覆盖相同的字段,它将抛出 TypeError: Cannot redefine property。

      ¥In legacy decorators, if superclass has a field decorated by @action, and subclass tries to override the same field, it will throw a TypeError: Cannot redefine property.

    • 在现代装饰器中,如果超类有一个由 @action 修饰的字段,而子类试图覆盖相同的字段,则允许覆盖该字段。但是,子类上的字段不是动作,除非它在子类声明中也用 @action 修饰。

      ¥In modern decorators, if superclass has a field decorated by @action, and subclass tries to override the same field, it's allowed to override the field. However, the field on subclass is not an action unless it's also decorated with @action in subclass declaration.

使用 observer 作为装饰器

¥Using observer as a decorator

mobx-react 中的 observer 函数既是一个函数,又是一个装饰器,可以在类组件上使用:

¥The observer function from mobx-react is both a function and a decorator that can be used on class components:

@observer
class Timer extends React.Component {
    /* ... */
}
← 配置 {🚀}从 MobX 4/5 迁移 {🚀} →
  • 启用装饰器
  • 使用装饰器
  • 使用 observer 作为装饰器
MobX v6.13 中文网 - 粤ICP备13048890号
Nodejs.cn 旗下网站