背景
上一份工作用了很久的mobx,对于它简洁的API、轻量级的特性非常欣赏。新的工作需要转为使用redux,搜了一下redux官方文档,没有看到migrate from mobx的文章,社区也很少有从mobx迁移到redux的介绍,于是自己边学习边记录一下二者的共通之处与不同点,也为后续需要的同学提供参考。
核心概念映射
concepts table
概念 | mobx | redux |
---|---|---|
状态 | observable state | store |
触发状态改变 | action | action, dispatch |
状态更新逻辑 | - | reducer |
派生值 | computed value | selector |
副作用 | reaction | - |
mobx 概念流程图

redux 概念流程图

概念详解
observable state vs. store
在mobx中,要想某个变量可以被其他地方自动追踪变化,需要将该变量标记为observable,标记的方法按照变量的类型有类装饰器、属性装饰器、函数几种。读取变量的值非常方便,当做普通值使用即可。详见官方文档中的用法。 在redux中,"可观察变量"的概念是被弱化的,即所有利用redux定义的变量都被写入一个全局的store变量中。如果需要获取store中的某个属性的话,需要使用 store.getState()
来读取。
action vs. dispatch
在mobx中,action的写法是非常自由的,通常为一个接收新值的函数,内部将旧值替换为新值,类似于react的state hook中的setter。对变量改动范围仅限于这个局部属性,接下来受影响的派生值和副作用也仅限于与之相关的局部属性。可以认为它的action是没有boilerplate code的,非常简洁透明,而且影响范围也非常局部。 在redux中,action的写法是非常固定的,格式如下
typescript
const addTodoAction = {
type: 'todos/todoAdded',
payload: 'Buy milk'
}
个人认为这样写是为了方便reducer消费。相比mobx,boilerplate code比较明显。
[redux独有] reducer
个人认为reducer是redux的核心,它定义了数据更新的所有逻辑,其他的概念如state, action 都是为了reducer服务的。由于要适配action的boilerplate code,一个常见的reducer通常是如下格式
typescript
// store
const initialState = { value: 0 }
function counterReducer(state = initialState, action) {
// action对号入座,这里也常常使用swtich-case语句首先
if (action.type === 'counter/incremented') {
return {
// 复制原始值,这一步必不可少,否则整体state的其他变量将受影响
...state,
// 更新需要更新的值
value: state.value + 1
}
}
// 非已知的action,返回原始值
return state
}
computed value vs. selectors
在mobx中,computed value可以视为和vue的计算属性是等同的概念。mobx官网的第一篇文章中有这样一句话,可见它所推崇的是尽可能使用自动计算的派生值。它认为大部分变量应该像Excel表格中的计算公式单元格一样自动更新。有了计算属性,派生值的更新变得非常的清晰和便捷。
Anything that can be derived from the application state, should be. Automatically.
可以使用装饰器或者makeAutoObservable
来将变量标注为计算属性,详见官方文档。一个class写法的示例如下
typescript
import { makeObservable, observable } from "mobx"
class OrderLine {
price = 0
amount = 1
constructor(price) {
// 这个函数使得属性自动变成observable, getter自动变成计算属性
makeAutoObservable(this)
this.price = price
}
// 计算属性
get total() {
console.log("Computing...")
return this.price * this.amount
}
}
在redux中,selector的直接定义是从store中读取部分state的值,但是我们完全可以把它当做书写计算属性的逻辑的地方,示例如下
typescript
// 定义selector
const selectTotalCompletedTodos = state => {
const completedTodos = state.todos.filter(todo => todo.completed)
return completedTodos.length
}
// 组件内
const completedTodos = useSelector(selectTotalCompletedTodos)
虽然二者能实现同样的功能,但是在性能上是存在差距的,这里引用DeepSeek的回答
虽然两者都能实现派生状态管理,但 Redux selectors 需要显式优化才能达到 MobX computed 的自动化水平。选择应基于:项目规模、团队习惯、对不可变数据的需求程度。大型复杂应用推荐 Redux+Reselect+RTK Query,快速迭代项目更适合 MobX 的响应式范式。
[mobx独有] reaction
个人认为mobx的reaction可以起到将react的useEffect提到组件外面执行的作用,从而将副作用单独管理,避免受组件渲染周期的影响。具体的写法有autorun
reaction
和 when
三种,详见官方文档。
总结
本文介绍了mobx和redux在概念上共通的部分,并且比较了写法和设计上的差异。当然,这两个库的使用方法和原理以及性能还有很多可以比较的内容,待后续对redux有了更多的实践再进行记录。