跳到主要内容

核心思想

Mobx 的核心思想是围绕响应式状态管理展开,通过 可观察对象(Observables) 储存状态、动作 (Actions) 修改状态、响应机制 自动同步状态变化到依赖项(如 React 组件、计算值、副作用),实现“状态变化自动驱动视图几衍生逻辑更新”的见解流程。

一、可观察对象(Observables):状态的“响应式容器”

可观察对象是 Mobx 状态管理的基础,用于定义应用中需要跟踪变化的状态数据(如组件的 propsstate 全局 store 中的属性)。通过 @observable 装饰器或 observable() 函数标记, Mobx 会自动追踪这些数据的读取和修改,当数据变化时通知所有依赖它的逻辑(如组件渲染、计算值更新)。

  • 类属性: 通过 @observable 装饰器标记类中的状态属性(需启用装饰器语法,或用 decorate 工具代替)

    import { observable, decorate } from 'mobx';

    class Todo {
    id = Math.random();
    @observable
    title = ''; // 可观察标题
    @observable
    finished = false; // 可观察的完成状态
    }

    // ES 5 环境替代方案

    class TodoE {
    id = Math.random();
    title = '';
    finished = false;
    }

    decorate(Todo, {
    title: observable,
    finished: observable,
    });
  • 原始值/引用值:observable() 函数可将原始值(如数字、字符串)或引用值(如对象、数组、Map)转换为可观察对象

    import { observable } from 'mobx';
    // 原始值的可观察容器,通过 `set`/`get` 修改/读取
    const count = observable.box(0);
    // 数组的可观察版本,修改元素会触发通知
    const todos = observable(['学习雷锋', '好榜样']);
    // 对象的可观察版本,修改属性会触发通知
    const user = observable({
    name: 'Tom',
    age: 86,
    });

核心特性

  • 自动追踪Mobx 通过 Proxy(MobX 5+) 或 Object.defineProperty (Mobx 4-)拦截可观察对象的 读取(getter)修改(setter) 操作,无需手动调用 setState 或 `forceUpdate
  • 感染性:默认情况下,可观察对象的所有属性购会递归转换成可观察(如 observable({a: 1, b : {c : 2}}) 中的 b.c 也会被观察),可通过 modifiers (如 asFlatasReference)调整这一行为

二、工作(action):状态修改的“唯一入口”

动作是 Mobx修改可观察对象状态 的唯一合法方式,用于封装所有改变状态的逻辑(如用户点击事件、API 请求后的数据更新)。通过 @action 装饰器或 action() 标记,Mobx 会追踪动作中的状态修改,并确保 状态变化的原子性 (即动作执行完成后,所有依赖状态才会更新)。

  • 类方法: 通过 @action 装饰器标记类中的状态修改方法

    import { observable, action, decorate } from 'mobx';

    class TodoStore {
    @observable
    todos = [];

    // 添加动作
    @action
    addTodo(title) {
    this.todos.push({
    id: Math.random(),
    title,
    finished: false,
    });
    }

    // 标记完成动作
    @action
    toggleTodo(id) {
    const todo = this.todos.find(t => t.id === id);
    if (todo) {
    todo.finished = !todo.finished;
    }
    }
    }

    // ES5 环境替代方案
    class TodoStoreES5 {
    todos = [];

    addTodo(title) {
    this.todos.push({
    id: Math.random(),
    title,
    finished: false,
    });
    }

    toggleTodo(id) {
    const todo = this.todos.find(t => t.id === id);
    if (todo) {
    todo.finished = !todo.finished;
    }
    }
    }

    decorate(todoStoreES5, {
    todos: observable,
    addTodo: action,
    toggleTodo: action,
    });
  • 一次性动作runInAction() 函数用于在非动作上下文(如异步回调、事件处理函数)中临时创建动作,确保状态修改的非法性

    import { action, runInaction } from 'mobx';

    class UserStore {
    @observable
    user = null;

    async fetchUser(id) {
    const response = await fetch(`api/users/${id}`);
    const user = await response.json();
    // 必须在动作中修改动态(异步回调不是动作)
    runInAction(() => {
    this.user = user;
    });
    }
    }

核心特性

  • 原子性:动作执行过程中,Mobx 会缓存所有状态修改,知道动作完成完成后再统一通知依赖项,避免中间状态导致的 UI 闪烁
  • 严格模式:通过 configure({ enforceActions: "always"}) 启用严格模式后,禁止在动作外修改状态,强制开发者封装状态修改逻辑,提升代码可维护性

三、响应式机制:状态与视图的“自动同步桥梁”

响应式机制是 Mobx 的核心灵魂,通过 自动追踪依赖触发更新 ,实现“状态变化 ➞ 视图/衍生逻辑自动更新”的流程。其核心逻辑是:

  • 依赖收集: 当计算值(computed)或反应(reactions,如 React 组件渲染)读取可观察对象时,Mobx 会记录“该计算值/反应依赖于哪些可观察对象”
  • 变化通知:当可观察对象被动作修改后,Mobx 会通知所有依赖他的计算值/反应
  • 更新触发:计算值会自动重新计算(如 unfinishedTodoCount 会根据 todos 的变化重新计算统计),返回会执行副作用(如 React 组件重新渲染、发送网络请求)

1. 响应式机制 -- 计算值

通过 @computed 状态器或 computed() 函数定义,基于可观察对象自动计算衍生值(如统计未完成的 todo 数量)。计算值具有惰性求值特性(仅当依赖的可观察对象变化且被使用时才会重新计算)

import { observable, computed, action } from 'mobx';

class TodoStore {
@observable
todos = [];

// 未完成的 todo 数量(依赖 todos )
@computed
get unfinishedTodoCount() {
return this.todos.filter(todo => !todo.finished).length;
}

@action
addTodo(title) {
this.todos.push({
id: Math.random(),
title,
finished: false,
});
}
}

2. 响应式机制 -- 反应

通过 autorun()reaction()when() 函数定义,用于处理 副作用 (如更新 UI、发动网络请求)。其中, autorun() 是最常用的反应类型,会自动追踪其回调函数中的可观察对象依赖,并在依赖变化时执行回调。

import { observable, autorun } from 'mobx';

const count = observable.box(0);

// 反应:当 count 变化时,打印日志(依赖 count)
autorun(() => {
console.log(`Count is now: ${count.get()}`);
});

count.set(1); // 输出:count is now:1

count.set(2); // 输出:count is now:2

3. 响应式机制 -- 与 React 集成

通过 mobx-react 库的 observer 高阶组件或 useObserverHook,将 React 组件转化为“响应式组件”。当组件依赖的可观察对象变化时,observer 会自动触发组件重新渲染。

import { observer } from 'mobx-react';
import { TodoStore } from './store/TodoStore';

// 响应式组件:依赖 TodoStore 的 todos 和 unfinishedTodoCount
const TodoList = observer(({store}) => {
<div>
<h2>未办事件:{{store.unfinishedTodoCount }}</h2>
<ul>
{store.todos.map(todo => (
<li
key={todo.id}
style={{textDecoration: todo.finished
?
'line-through'
:
'none'}}>
{todo.title}
</li>))}
</ul>
</div>
});