MobX 🇺🇦

MobX 🇺🇦

  • API 参考
  • 中文
  • 한국어
  • 赞助商
  • GitHub

›介绍

介绍

  • 关于 MobX
  • 关于这份文档
  • 安装
  • MobX 的核心

MobX 核心

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

MobX 和 React

  • React 集成
  • React 优化 {🚀}

提示与技巧

  • 定义数据存储
  • 理解响应性
  • 子类化
  • 分析响应性 {🚀}
  • 带参数的计算值 {🚀}
  • MobX-utils {🚀}
  • 自定义可观察对象 {🚀}
  • 延迟可观察对象 {🚀}
  • 集合实用程序 {🚀}
  • 拦截和观察 {🚀}

微调

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

MobX 的核心

概念

MobX 在你的应用程序中区分以下三种概念

  1. 状态
  2. 动作
  3. 派生值

让我们仔细看看以下这些概念,或者你也可以在MobX 和 React 的 10 分钟入门中交互式地深入了解这些概念,并逐步构建一个简单的待办事项列表应用程序。

有些人可能在下面描述的概念中认出了“信号”的概念。这是正确的,MobX 是一个先驱式的基于信号的状态管理库。

1. 定义状态并使其可观察

状态是驱动你的应用程序的数据。通常,存在领域特定状态,比如待办事项列表,还存在视图状态,比如当前选中的元素。状态就像电子表格单元格,保存着值。

将状态存储在任何你喜欢的數據結構中:普通对象、数组、类、循环数据结构或引用。这对于 MobX 的工作机制来说无关紧要。只需确保所有你想要随时间改变的属性都被标记为observable,这样 MobX 就可以跟踪它们。

这里有一个简单的例子

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

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

    constructor(title) {
        makeObservable(this, {
            title: observable,
            finished: observable,
            toggle: action
        })
        this.title = title
    }

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

使用observable就像将对象的属性变成电子表格单元格。但与电子表格不同的是,这些值不仅可以是原始值,还可以是引用、对象和数组。

提示:喜欢类、普通对象或装饰器?MobX 支持多种风格。

这个例子可以使用makeAutoObservable进行简化,但通过明确地展示,我们可以更详细地展示不同的概念。请注意,MobX 不强制执行对象风格,普通对象也可以使用,装饰器还可以用于更简洁的类。有关更多详细信息,请参阅页面。

但是toggle呢,为什么我们把它标记为action?

2. 使用动作更新状态

动作是任何改变状态的代码段。用户事件、后端数据推送、计划事件等等。动作就像一个用户,在电子表格单元格中输入一个新值。

在上面的Todo模型中,你可以看到我们有一个toggle方法,它改变了finished的值。finished被标记为observable。建议将任何改变observable的代码段标记为action。这样 MobX 就可以自动应用事务,以实现轻松的最佳性能。

使用动作可以帮助你结构化代码,并防止你在不经意间改变状态。在 MobX 术语中,修改状态的方法被称为动作。与视图形成对比,视图是基于当前状态计算新的信息。每个方法最多应该服务于这两个目标中的一个。

3. 创建自动响应状态变化的派生值

任何可以从状态中推导出来的东西,而无需任何进一步的交互,都是一个派生值。派生值以多种形式存在

  • 用户界面
  • 派生数据,比如剩余的todos数量
  • 后端集成,例如将更改发送到服务器

MobX 区分两种类型的派生值

  • 计算值,它总是可以使用纯函数从当前可观察状态中推导出来
  • 反应,当状态发生变化时需要自动发生的副作用(在命令式编程和响应式编程之间架起桥梁)

在使用 MobX 时,人们往往过度使用反应。黄金法则是在你想要根据当前状态创建值时,始终使用computed。

3.1. 使用计算值建模派生值

要创建计算值,请使用 JS getter 函数get定义一个属性,并使用makeObservable将其标记为computed。

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

class TodoList {
    todos = []
    get unfinishedTodoCount() {
        return this.todos.filter(todo => !todo.finished).length
    }
    constructor(todos) {
        makeObservable(this, {
            todos: observable,
            unfinishedTodoCount: computed
        })
        this.todos = todos
    }
}

MobX 将确保unfinishedTodoCount在添加待办事项或修改其中一个finished属性时自动更新。

这些计算类似于 MS Excel 等电子表格程序中的公式。它们会自动更新,但只有在需要时才会更新。也就是说,如果有东西对它们的输出感兴趣的话。

3.2. 使用反应建模副作用

为了让用户能够在屏幕上看到状态或计算值的变化,需要一个反应来重新绘制 GUI 的一部分。

反应类似于计算值,但它们不会产生信息,而是产生副作用,比如打印到控制台、发出网络请求、增量更新 React 组件树以修补 DOM 等等。

简而言之,反应是响应式编程和命令式编程之间的桥梁。

到目前为止,最常用的反应形式是 UI 组件。请注意,可以从动作和反应中触发副作用。那些具有明确、显式起源的副作用(例如,在提交表单时发出网络请求)应该从相关的事件处理程序中显式触发。

3.3. 响应式 React 组件

如果你正在使用 React,你可以使用observer函数(来自你在安装过程中选择的绑定包)来使你的组件具有响应性。在本例中,我们将使用更轻量级的mobx-react-lite包。

import * as React from "react"
import { render } from "react-dom"
import { observer } from "mobx-react-lite"

const TodoListView = observer(({ todoList }) => (
    <div>
        <ul>
            {todoList.todos.map(todo => (
                <TodoView todo={todo} key={todo.id} />
            ))}
        </ul>
        Tasks left: {todoList.unfinishedTodoCount}
    </div>
))

const TodoView = observer(({ todo }) => (
    <li>
        <input type="checkbox" checked={todo.finished} onClick={() => todo.toggle()} />
        {todo.title}
    </li>
))

const store = new TodoList([new Todo("Get Coffee"), new Todo("Write simpler code")])
render(<TodoListView todoList={store} />, document.getElementById("root"))

observer 将 React 组件转换为它们渲染数据的派生值。在使用 MobX 时,没有智能组件或哑组件。所有组件都以智能方式渲染,但以哑方式定义。MobX 只需确保组件始终在需要时重新渲染,而且绝不会多余地渲染。

因此,上面的例子中的onClick处理程序将强制相应的TodoView组件重新渲染,因为它使用toggle动作,但只会导致TodoListView组件在未完成的任务数量发生变化时才重新渲染。如果你删除“剩余任务”行(或将其放入一个单独的组件中),那么TodoListView组件在勾选任务时将不再重新渲染。

要了解更多关于 React 如何与 MobX 协作的信息,请查看React 集成部分。

3.4. 自定义反应

您很少会用到它们,但可以使用 autorun、reaction 或 when 函数来创建它们,以适应您的具体情况。例如,以下 autorun 在 unfinishedTodoCount 数量发生变化时打印一条日志消息

// A function that automatically observes the state.
autorun(() => {
    console.log("Tasks left: " + todos.unfinishedTodoCount)
})

为什么每次 unfinishedTodoCount 发生变化时都会打印一条新消息?答案是这条经验法则

MobX 会对在跟踪函数执行期间读取的任何现有可观察属性做出反应。

要了解有关 MobX 如何确定需要对哪些可观察属性做出反应的更多信息,请查看 了解响应性 部分。

原则

MobX 使用单向数据流,其中操作更改状态,而状态反过来更新所有受影响的视图。

Action, State, View

  1. 所有派生在状态发生变化时会自动且原子地更新。因此,永远无法观察到中间值。

  2. 默认情况下,所有派生都以同步方式更新。这意味着,例如,操作可以在更改状态后安全地直接检查计算值。

  3. 计算值以延迟方式更新。任何未被积极使用的计算值都不会被更新,直到它被用于副作用(I/O)为止。如果视图不再使用,它将被自动垃圾回收。

  4. 所有计算值都应该是纯净的。它们不应该更改状态。

要了解有关背景上下文的更多信息,请查看 MobX 背后的基本原理。

试一试!

您可以在 CodeSandbox 上亲自尝试以上示例。

代码风格检查

如果您发现难以采用 MobX 的思维模型,请将其配置为非常严格,并在您偏离这些模式时在运行时向您发出警告。查看 代码风格检查 MobX 部分。

← 安装可观察状态 →
  • 概念
    • 1. 定义状态并使其可观察
    • 2. 使用操作更新状态
    • 3. 创建自动响应状态变化的派生
  • 原则
  • 试一试!
  • 代码风格检查
MobX 🇺🇦
文档
关于 MobXMobX 的要点
社区
GitHub 讨论(新)Stack Overflow
更多
星标