这些库都用于处理应用中的数据流动和状态变化,但设计理念不同。redux 强调不可变数据和集中式存储;mobx 通过可变对象和自动依赖追踪简化流程;effector 结合函数式编程与类型安全,无需 Provider;rxjs 则是强大的响应式流库,擅长处理复杂异步事件序列。
这四个库都旨在解决前端应用中的数据管理问题,但它们的底层逻辑和适用场景有很大区别。redux 是经典的集中式状态容器,mobx 主打响应式可变数据,effector 追求函数式与类型安全,而 rxjs 则是处理异步流的通用利器。让我们从实际开发角度对比它们的实现方式。
redux 维护一个单一的全局状态树,状态是只读的。
// redux: 单一存储树
import { configureStore, createSlice } from '@reduxjs/toolkit';
const counterSlice = createSlice({
name: 'counter',
initialState: 0,
reducers: { increment: (state) => state + 1 }
});
const store = configureStore({ reducer: counterSlice.reducer });
// 状态存储在 store.getState()
mobx 将普通对象变为可观察对象,自动追踪依赖。
// mobx: 可观察对象
import { makeAutoObservable } from 'mobx';
class CounterStore {
count = 0;
constructor() { makeAutoObservable(this); }
increment() { this.count++; }
}
const store = new CounterStore();
// 直接修改 store.count 即可
effector 区分状态(Store)和事件(Event)。
// effector: Store 与 Event
import { createStore, createEvent } from 'effector';
const $count = createStore(0);
const increment = createEvent();
// 连接事件与状态
$count.on(increment, (state) => state + 1);
// 触发事件 increment()
rxjs 基于 Observable 流,数据随时间推送。
// rxjs: 行为主题流
import { BehaviorSubject } from 'rxjs';
const $count = new BehaviorSubject(0);
// 通过 next 推送新值
$count.next($count.getValue() + 1);
// 订阅流获取数据
redux 必须通过 dispatch 发送动作。
// redux: 发送动作
store.dispatch({ type: 'counter/increment' });
// 或使用 Toolkit 生成的 action
store.dispatch(counterSlice.actions.increment());
mobx 直接修改属性,动作包装可选。
// mobx: 直接修改
store.count = store.count + 1;
// 或在 action 方法内
store.increment();
effector 调用事件函数触发更新。
// effector: 调用事件
increment();
// 或通过 carry payload
const setCount = createEvent();
$count.on(setCount, (_, payload) => payload);
setCount(10);
rxjs 调用 next 方法推送数据。
// rxjs: 推送数据
$count.next(10);
// 订阅者会自动收到新值
redux 使用中间件处理副作用。
// redux: Thunk 异步
const fetchUser = () => async (dispatch) => {
const res = await api.getUser();
dispatch({ type: 'user/set', payload: res });
};
mobx 使用 async action 或 flow。
// mobx: 异步 action
class Store {
async fetchUser() {
const res = await api.getUser();
this.user = res; // 自动触发更新
}
}
effector 使用 Effect 单元处理副作用。
// effector: Effect
import { createEffect } from 'effector';
const fetchUser = createEffect(async (id) => {
return await api.getUser(id);
});
// 监听完成事件
fetchUser.done.watch(({ result }) => console.log(result));
rxjs 使用操作符处理异步流。
// rxjs: 操作符处理
import { switchMap } from 'rxjs/operators';
inputChanges$.pipe(
debounceTime(300),
switchMap(val => api.search(val))
).subscribe(result => console.log(result));
redux 需要 Provider 包裹应用。
// redux: React 集成
import { useSelector, useDispatch } from 'react-redux';
function Counter() {
const count = useSelector(state => state);
const dispatch = useDispatch();
return <button onClick={() => dispatch(increment())}>{count}</button>;
}
mobx 使用 observer 包裹组件。
// mobx: React 集成
import { observer } from 'mobx-react-lite';
const Counter = observer(({ store }) => {
return <button onClick={() => store.increment()}>{store.count}</button>;
});
effector 使用 useStore Hook。
// effector: React 集成
import { useStore } from 'effector-react';
function Counter() {
const count = useStore($count);
return <button onClick={() => increment()}>{count}</button>;
}
rxjs 通常配合自定义 Hook 使用。
// rxjs: React 集成
import { useState, useEffect } from 'react';
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
const sub = $count.subscribe(setCount);
return () => sub.unsubscribe();
}, []);
return <div>{count}</div>;
}
虽然实现方式不同,但这些库在解决数据流问题上有许多共通之处。
// 所有库都支持这种模式:数据变 -> 视图变
// Redux: dispatch -> reducer -> store -> view
// MobX: set property -> reaction -> view
// Effector: event -> store -> view
// RxJS: next -> subscribe -> view
// Redux: combineReducers
// MobX: 多个 Store 类实例
// Effector: 多个 createStore
// RxJS: 多个 Subject 组合
// Redux: Redux DevTools
// MobX: MobX DevTools
// Effector: Effector Inspector
// RxJS: RxJS DevTools (较少用)
// 都有对应的框架绑定包
// react-redux, mobx-react-lite, effector-react, react-rxjs
| 特性 | redux | mobx | effector | rxjs |
|---|---|---|---|---|
| 数据可变性 | ❌ 不可变 | ✅ 可变 | ❌ 不可变 (Store) | ✅ 可变 (Stream) |
| 样板代码 | 🧱 较多 (需 Toolkit) | 🪶 极少 | 🪶 少 | 🧱 较多 |
| 学习曲线 | 📈 中等 | 📉 低 | 📈 中等 | 📈 高 |
| 异步处理 | 🕰️ 中间件 (Thunk) | 🌊 Flow/Action | ⚡ Effect 单元 | 🎹 操作符 |
| React 集成 | 🔌 Provider 必需 | 👁️ Observer 包裹 | 🎣 Hook (无 Provider) | 🧵 手动订阅 |
| 类型支持 | ✅ 好 (需配置) | ✅ 好 | 🏆 极佳 (推断强) | ✅ 好 |
redux 像是一个标准化的仓库管理系统 🏢 — 适合需要严格流程、多人协作和长期维护的大型项目。配合 Redux Toolkit 可以降低使用门槛。
mobx 像是一个智能记事本 📝 — 适合追求开发速度、代码简洁且逻辑相对直接的应用。它的魔法让状态管理变得透明。
effector 像是一套精密的函数式工具集 🛠️ — 适合重视类型安全、性能优化且希望摆脱 Provider 嵌套的团队。它在复杂逻辑处理上非常优雅。
rxjs 像是一条强大的数据流水线 🏭 — 适合处理高频事件、WebSocket 连接或复杂异步组合场景。它不仅是状态管理,更是事件处理的核心。
核心思路:如果只是管理 UI 状态,redux 或 effector 更合适;如果涉及复杂事件流,rxjs 不可替代;如果想要最快上手,mobx 是首选。根据团队技术栈和项目复杂度做出选择 — 没有绝对最好的工具,只有最适合场景的方案。
选择 redux 如果你需要严格的可预测状态管理、时间旅行调试以及庞大的生态系统支持。配合 Redux Toolkit 使用,适合大型团队协作和企业级应用。
选择 effector 如果你需要强大的类型推导、无需 Provider 的架构以及高性能的细粒度更新。适合对 TypeScript 支持要求高且希望减少样板代码的大型项目。
选择 mobx 如果你偏好面向对象的编程风格,希望用最少的代码实现响应式状态,且不介意魔法般的自动依赖追踪。适合快速迭代的中小型应用。
选择 rxjs 如果你的应用涉及复杂的异步事件流、WebSocket 数据流或需要高级操作符来处理数据转换。适合实时数据面板或复杂交互场景。
Redux is a predictable state container for JavaScript apps.
It helps you write applications that behave consistently, run in different environments (client, server, and native), and are easy to test. On top of that, it provides a great developer experience, such as live code editing combined with a time traveling debugger.
You can use Redux together with React, or with any other view library. The Redux core is tiny (2kB, including dependencies), and has a rich ecosystem of addons.
Redux Toolkit is our official recommended approach for writing Redux logic. It wraps around the Redux core, and contains packages and functions that we think are essential for building a Redux app. Redux Toolkit builds in our suggested best practices, simplifies most Redux tasks, prevents common mistakes, and makes it easier to write Redux applications.
The recommended way to start new apps with React and Redux Toolkit is by using our official Redux Toolkit + TS template for Vite, or by creating a new Next.js project using Next's with-redux template.
Both of these already have Redux Toolkit and React-Redux configured appropriately for that build tool, and come with a small example app that demonstrates how to use several of Redux Toolkit's features.
# Vite with our Redux+TS template
# (using the `degit` tool to clone and extract the template)
npx degit reduxjs/redux-templates/packages/vite-template-redux my-app
# Next.js using the `with-redux` template
npx create-next-app --example with-redux my-app
We do not currently have official React Native templates, but recommend these templates for standard React Native and for Expo:
npm install @reduxjs/toolkit react-redux
For the Redux core library by itself:
npm install redux
For more details, see the Installation docs page.
The Redux core docs are located at https://redux.js.org, and include the full Redux tutorials, as well usage guides on general Redux patterns:
The Redux Toolkit docs are available at https://redux-toolkit.js.org, including API references and usage guides for all of the APIs included in Redux Toolkit.
The Redux Essentials tutorial is a "top-down" tutorial that teaches "how to use Redux the right way", using our latest recommended APIs and best practices. We recommend starting there.
The Redux Fundamentals tutorial is a "bottom-up" tutorial that teaches "how Redux works" from first principles and without any abstractions, and why standard Redux usage patterns exist.
The #redux channel of the Reactiflux Discord community is our official resource for all questions related to learning and using Redux. Reactiflux is a great place to hang out, ask questions, and learn - please come and join us there!
Redux is a valuable tool for organizing your state, but you should also consider whether it's appropriate for your situation. Please don't use Redux just because someone said you should - instead, please take some time to understand the potential benefits and tradeoffs of using it.
Here are some suggestions on when it makes sense to use Redux:
Yes, these guidelines are subjective and vague, but this is for a good reason. The point at which you should integrate Redux into your application is different for every user and different for every application.
For more thoughts on how Redux is meant to be used, please see:
The whole global state of your app is stored in an object tree inside a single store. The only way to change the state tree is to create an action, an object describing what happened, and dispatch it to the store. To specify how state gets updated in response to an action, you write pure reducer functions that calculate a new state based on the old state and the action.
Redux Toolkit simplifies the process of writing Redux logic and setting up the store. With Redux Toolkit, the basic app logic looks like:
import { createSlice, configureStore } from '@reduxjs/toolkit'
const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0
},
reducers: {
incremented: state => {
// Redux Toolkit allows us to write "mutating" logic in reducers. It
// doesn't actually mutate the state because it uses the Immer library,
// which detects changes to a "draft state" and produces a brand new
// immutable state based off those changes
state.value += 1
},
decremented: state => {
state.value -= 1
}
}
})
export const { incremented, decremented } = counterSlice.actions
const store = configureStore({
reducer: counterSlice.reducer
})
// Can still subscribe to the store
store.subscribe(() => console.log(store.getState()))
// Still pass action objects to `dispatch`, but they're created for us
store.dispatch(incremented())
// {value: 1}
store.dispatch(incremented())
// {value: 2}
store.dispatch(decremented())
// {value: 1}
Redux Toolkit allows us to write shorter logic that's easier to read, while still following the original core Redux behavior and data flow.
You can find the official logo on GitHub.
This project adheres to Semantic Versioning. Every release, along with the migration instructions, is documented on the GitHub Releases page.