新工具 2026年05月07日

别被 MobX 的优雅骗了:Zustand 才是更适合大多数 React 项目的状态管理

by BLL

别被 MobX 的优雅骗了:Zustand 才是更适合大多数 React 项目的状态管理

大家好,今天我们来聊一个前端项目里特别常见、但又特别容易吵起来的话题:状态管理到底选 Zustand 还是 MobX

我先把结论放前面。MobX 不是不好,甚至可以说它很顺手,很优雅,很多时候你一上手就会觉得“这东西真省事”。但问题也正出在这里。它太顺了,顺到很多隐藏复杂性会被它藏起来。项目一小,这不算事;项目一大,团队一换人,事情就开始变味了。

Zustand 的优势,不是它比 MobX 更“高级”,而是它更像一套适合大多数 React 项目的工程解法。它把状态流、组件订阅、更新方式都压得很平,不花哨,但很稳。

所以这篇文章我不打算站队。我想讲清楚一件事:为什么在真实项目里,Zustand 往往比 MobX 更实用。


MobX 为什么会让人觉得很舒服?

好,先别急着批评 MobX。它吸引人的地方,是真的明显。

MobX 官方一直强调几件事:它简单、可扩展、战斗验证过,而且它的核心理念是把状态、动作、派生值分开。你写普通 JavaScript 对象、数组、类就能做响应式,不需要把一切都包成很重的模板。

这带来什么结果呢?

  1. 写起来很顺
  2. 更新状态很自然
  3. 派生状态也很直观
  4. 响应式追踪是自动的

就是说,你不用手动把哪些组件该刷新、哪些依赖该重算写得很细。MobX 会在运行时帮你追踪“谁读了谁”,然后只刷新需要刷新的地方。

对于小团队、原型阶段、或者已经很熟 MobX 的人来说,这种体验确实很爽。你会觉得自己少写了很多样板代码,也少做了很多重复劳动。

这个地方我不反对。MobX 的优雅,是真的优雅。


但问题也在这里:它太“会自己做主”了

MobX 最大的问题,不是不能用,而是它太容易把复杂性藏在运行时里。

你看它的逻辑,本质上是“读取什么,追踪什么;谁变了,谁重渲染”。这个机制本身没问题,甚至很强。但对团队协作来说,强不等于省心。

第一,数据流不够显式

在 Zustand 里,谁在读状态、谁在改状态,通常都很清楚。你看 selector,能知道组件订阅了什么;你看 action,能知道状态从哪儿变。

MobX 不是这个路子。它更像是“你先写,系统帮你看”。短期看挺省事,长期看就容易出现一种情况:状态是怎么传到这里的,没人第一眼看得出来

这就会带来一个问题,调试时你得先理解它的隐式依赖关系,再去找问题。项目里人越多,这件事越贵。

第二,心智负担更偏运行时

MobX 的响应式是运行时自动追踪的。这个优点在小项目里是优点,在复杂项目里也可能变成负担。

因为一旦你遇到一个“为什么这个组件又刷新了”“为什么这个值没按我想的变化”的问题,你就得回头分析 observables、actions、computed、reactions 之间的关系。不是说分析不了,而是它的解释成本更高。

这就像一辆车开起来很顺,但你要修它的时候,得先理解它的内部逻辑。

第三,团队规范更难统一

MobX 很自由。自由当然好,但自由也意味着团队必须自己建立足够强的约束。

如果没有统一的 store 组织方式、命名方式、派生值分层方式,MobX 很容易长成一堆“谁都能改、谁都能读、谁都能顺手塞逻辑”的东西。到了这个阶段,代码看起来没什么大问题,实际维护起来会很累。

所以说,MobX 的问题不是“它不专业”,而是它把很多约束留给了团队自己补。


Zustand 为什么更实用?

好,接下来看看 Zustand。

Zustand 官方的定位很直接:small、fast、scalable,API 是 hook 风格,不啰嗦,也不强行规定你怎么组织业务。

这个地方我觉得它很聪明。它没有把自己包装成一个“哲学系统”,它就是把一件事做简单:让你用 hook 管状态。

1. API 小,学习成本低

Zustand 最好的地方,就是它小。

你创建一个 store,就是一个 hook。组件里直接用 selector 订阅需要的片段,不需要 Provider 套一层,不需要再引入一套额外的上下文结构。

这会带来什么?

  • 读代码的人一眼知道状态从哪来
  • 新成员上手快
  • 不容易把架构搞得太重
  • 适合页面级、模块级、跨组件状态

这个地方其实非常工程化。很多项目死就死在“状态管理方案比业务还重”。Zustand 的好处,就是它不会逼你把这件事做得太复杂。

2. 状态更新方式更直白

Zustand 的 set 很朴素,很多时候就是“改哪个字段、怎么改”。

这比 MobX 那种自动追踪的感觉更显式。显式的好处不是“更漂亮”,而是更容易排错

你看 Zustand 的 store:

import { create } from 'zustand'

const useBearStore = create((set) => ({
  bears: 0,
  increase: () => set((state) => ({ bears: state.bears + 1 })),
  reset: () => set({ bears: 0 }),
}))

很短,也很直接。谁在改什么,一眼能看出来。

3. 组件订阅更精细

Zustand 的另一个优势,是它默认就支持 selector 订阅。

就是说,组件只关心自己需要的那一小块状态,不会因为整个 store 变化就乱刷新。对于中大型 React 项目来说,这很重要。因为性能问题很多时候不是“模型太慢”,而是“刷新太多”。

而且 Zustand 还提供了 useShallow、中间件、persistdevtoolsimmer 这些扩展能力。也就是说,它底层保持轻,但真需要功能的时候,你也能往上加。

4. 组合方式更适合 React 生态

这个地方也很关键。

Zustand 的核心就是 hook,这意味着它和 React 的使用方式天然贴得很近。你不用额外学习一套响应式模型,就能把状态放进组件体系里。

对大多数 React 团队来说,这种“贴着 React 走”的方案,实际落地会更舒服。


一张表看清楚差别

维度 MobX Zustand
上手体验 很顺,很自然 很轻,很直接
数据流 偏隐式,运行时追踪 偏显式,hook + selector
调试成本 中到高 低到中
团队一致性 依赖规范 更容易统一
适合场景 复杂响应式模型、熟悉 MobX 的团队 大多数 React 项目
扩展方式 响应式体系本身很强 通过中间件逐步加能力

这个表不是说 MobX 不行。它只是说明:如果你的目标是让项目更稳、更容易维护、团队更容易达成一致,Zustand 通常更合适。


那 MobX 什么时候还值得用?

这个问题也得说清楚,不然就太偏了。

MobX 不是没有价值。它在这些场景里依然很有吸引力:

  • 你们团队已经非常熟 MobX
  • 你要表达的是一个复杂的领域模型
  • 你很在意自动派生和响应式表达
  • 项目本身不是典型的“React 页面状态管理”问题

也就是说,如果你做的不是普通 React 应用,而是更偏模型驱动、状态关系复杂、领域逻辑重的系统,MobX 依然有它的位置。

但如果你问我“大多数 React 项目默认选什么更稳”,我还是会偏向 Zustand。原因很简单:它让事情更少绕路。


我自己的结论

好,最后收一下。

MobX 的优雅,来自它把状态变化做得很自动;Zustand 的实用,来自它把状态变化做得很清楚。

这两种路线没有绝对的高低。问题在于,真实项目里最缺的,往往不是“更聪明的响应式系统”,而是更少的解释成本、更稳的团队协作、和更容易维护的状态边界

从这个角度看,Zustand 更像一把顺手的工具。它不试图替你做太多决定,但它把最关键的几件事做对了:

  1. 让状态读取更直接
  2. 让状态更新更明确
  3. 让组件订阅更轻
  4. 让团队协作更稳

所以说,Zustand 比 MobX 更实用,不是因为它“更强”,而是因为它更少制造额外复杂度。

这就是大多数 React 项目真正需要的东西。