探索 MobX 的组件刷新机制:以函数组件为例

33 阅读3分钟

探索 MobX 的组件刷新机制:以函数组件为例

在 React 中,状态驱动视图是一切的核心。MobX 作为一个响应式状态管理库,以其优雅的响应式编程模型和自动化的依赖追踪机制,被广泛应用于中大型前端项目中。

本文将通过一个简单的函数组件例子,深入探讨 MobX 是如何做到 自动追踪依赖并触发组件刷新 的。


一、案例代码分析

我们从一个简单的 MobX + React 函数组件的例子出发:

1. Store 层(状态源)

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

class CounterStore {
  count = 0;

  constructor() {
    makeObservable(this, {
      count: observable,
      increment: action,
    });
  }

  increment() {
    this.count++;
  }
}

const counterStore = new CounterStore();
export default counterStore;

2. UI 层(函数组件)

import React from "react";
import { Observer, inject } from "mobx-react";

const App = inject("counterStore")((props) => {
  const { counterStore } = props;

  return (
    <Observer>
      {() => (
        <div>
          <h1>Count: {counterStore.count}</h1>
          <button onClick={() => counterStore.increment()}>增加</button>
        </div>
      )}
    </Observer>
  );
});

export default App;

你会发现:每点击一次按钮,count 会加 1,页面也会自动刷新。MobX 是如何做到这一点的?


二、MobX 刷新机制的原理

1. observer 是入口

组件中的 Observerobserver()(HOC)就是 MobX 监听依赖的入口。

mobx-react-lite 的源码中,observer(fn) 实际会包裹传入的组件,并通过 useObserver() 进行依赖追踪:

let observerComponent = (props, ref) => {
  return useObserver(() => render(props, ref), baseComponentName)
}

2. useObserver 做了什么?

这是核心。我们来看下 useObserver 的关键部分:

const renderResult = reaction.track(() => {
  renderResult = render(); // 执行组件的渲染逻辑
});

这一行做了两件事:

  • 执行 render 函数(即组件渲染)
  • 在执行过程中收集所有访问的 observable

为什么能“收集依赖”?这就涉及到 MobX 的底层响应系统了。


三、深入原理:MobX 如何做到自动刷新组件?

MobX 能自动刷新组件,靠的是 响应式系统 + 依赖追踪 + 渲染订阅,简单来说分为以下三步:


步骤 1:依赖收集(track)

MobX 对 observable 数据使用了 Proxy 代理,通过 get 方法拦截访问。当组件渲染时读取了 counterStore.count,MobX 就知道这个组件依赖了这个数据。

这就叫 依赖收集(dependency tracking)


步骤 2:关系建立(subscribe)

每个组件在 observer() 包裹后,MobX 会为它创建一个 Reaction 实例。这个 Reaction 就是一个“副作用函数”,代表“当依赖变了,就要重新执行我”。

于是 MobX 会把这个 Reaction 挂到 counterStore.count 的依赖列表中,表示:

“当 count 被修改时,要通知这个 Reaction 重新执行。”


步骤 3:触发更新(reaction.run)

当你调用 counterStore.increment() 时,MobX 会通过 set 拦截到对 count 的赋值,然后通知它所有依赖的 Reaction

this.count++; // 触发 setter -> 通知依赖的 Reaction -> 执行组件的更新

在函数组件中,这一步会通过 React 的 useSyncExternalStore API 去强制组件刷新。


四、架构类比总结

我们可以用下面的架构关系来理解 MobX:

组件 Observer
     |
     --> 创建 Reaction(响应函数)
              |
              --> 在渲染时 track(),记录访问的 observable
                            |
                            --> observable 属性注册 Reaction 为订阅者
                                         |
当属性变化时 set() -> 通知 Reaction -> 强制刷新组件

一句话总结:

MobX 会在组件渲染时自动记录所访问的状态,并在这些状态变更时自动触发组件更新。


五、关键角色回顾

名称作用
observable将普通数据变成响应式数据(内部通过 Proxy 实现)
reaction表示一个“副作用”,当依赖的数据变化时会重新执行
observer把组件变成响应式组件,会自动监听它内部访问的 observable
track执行时收集依赖(被哪个 observable 读取了)
useSyncExternalStoreReact 18 中的底层 hook,用于响应式订阅并触发组件更新

六、写在最后

MobX 是一个非常优雅的响应式状态管理库,它的设计理念来自响应式编程,通过“自动依赖追踪 + 精准更新”的机制,让组件只在真正需要的时候才刷新,从而大大提升了性能。

理解 MobX 的更新机制,不仅能更好地使用它,也有助于你理解前端响应式编程模型的核心本质。