redux vs effector vs mobx vs rxjs
前端状态管理与响应式流方案对比
reduxeffectormobxrxjs类似的npm包:

前端状态管理与响应式流方案对比

这些库都用于处理应用中的数据流动和状态变化,但设计理念不同。redux 强调不可变数据和集中式存储;mobx 通过可变对象和自动依赖追踪简化流程;effector 结合函数式编程与类型安全,无需 Provider;rxjs 则是强大的响应式流库,擅长处理复杂异步事件序列。

npm下载趋势

3 年

GitHub Stars 排名

统计详情

npm包名称
下载量
Stars
大小
Issues
发布时间
License
redux54,483,61661,480290 kB153 年前MIT
effector04,8531.59 MB1651 年前MIT
mobx028,2104.84 MB455 天前MIT
rxjs031,6944.5 MB1902 年前Apache-2.0

前端状态管理与响应式流:Effector vs MobX vs Redux vs RxJS

这四个库都旨在解决前端应用中的数据管理问题,但它们的底层逻辑和适用场景有很大区别。redux 是经典的集中式状态容器,mobx 主打响应式可变数据,effector 追求函数式与类型安全,而 rxjs 则是处理异步流的通用利器。让我们从实际开发角度对比它们的实现方式。

🏗️ 核心数据模型:存储 vs 可观察对象 vs 流

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 将普通对象变为可观察对象,自动追踪依赖。

  • 数据可变,直接修改属性即可触发更新。
  • 类似 Excel 单元格,改动自动传播。
// mobx: 可观察对象
import { makeAutoObservable } from 'mobx';

class CounterStore {
  count = 0;
  constructor() { makeAutoObservable(this); }
  increment() { this.count++; }
}

const store = new CounterStore();
// 直接修改 store.count 即可

effector 区分状态(Store)和事件(Event)。

  • 状态是带值的单元,事件是触发器。
  • 无需 Provider 包裹,直接导入使用。
// effector: Store 与 Event
import { createStore, createEvent } from 'effector';

const $count = createStore(0);
const increment = createEvent();

// 连接事件与状态
$count.on(increment, (state) => state + 1);
// 触发事件 increment()

rxjs 基于 Observable 流,数据随时间推送。

  • 状态通常用 BehaviorSubject 保存。
  • 擅长处理连续数据流而非静态状态。
// rxjs: 行为主题流
import { BehaviorSubject } from 'rxjs';

const $count = new BehaviorSubject(0);
// 通过 next 推送新值
$count.next($count.getValue() + 1);
// 订阅流获取数据

✍️ 更新状态:Dispatch vs 直接赋值 vs 触发事件

redux 必须通过 dispatch 发送动作。

  • 不能直接修改状态。
  • 动作对象描述发生了什么。
// redux: 发送动作
store.dispatch({ type: 'counter/increment' });
// 或使用 Toolkit 生成的 action
store.dispatch(counterSlice.actions.increment());

mobx 直接修改属性,动作包装可选。

  • 代码最少,直观易懂。
  • 在 strict 模式下需在 action 中修改。
// mobx: 直接修改
store.count = store.count + 1;
// 或在 action 方法内
store.increment();

effector 调用事件函数触发更新。

  • 事件是普通函数,调用即触发。
  • 逻辑通过 sample 或 on 连接。
// effector: 调用事件
increment();
// 或通过 carry payload
const setCount = createEvent();
$count.on(setCount, (_, payload) => payload);
setCount(10);

rxjs 调用 next 方法推送数据。

  • 观察者被动接收数据。
  • 需要手动管理订阅防止内存泄漏。
// rxjs: 推送数据
$count.next(10);
// 订阅者会自动收到新值

⏳ 处理异步:Thunk vs Flow vs Effect vs 操作符

redux 使用中间件处理副作用。

  • 常用 Redux Thunk 或 Redux Saga。
  • 异步逻辑写在 action creator 中。
// redux: Thunk 异步
const fetchUser = () => async (dispatch) => {
  const res = await api.getUser();
  dispatch({ type: 'user/set', payload: res });
};

mobx 使用 async action 或 flow。

  • async 函数自动变为 action。
  • 支持生成器函数处理复杂流程。
// mobx: 异步 action
class Store {
  async fetchUser() {
    const res = await api.getUser();
    this.user = res; // 自动触发更新
  }
}

effector 使用 Effect 单元处理副作用。

  • Effect 是声明式的异步处理器。
  • 自动处理 loading 和错误状态。
// effector: Effect
import { createEffect } from 'effector';

const fetchUser = createEffect(async (id) => {
  return await api.getUser(id);
});
// 监听完成事件
fetchUser.done.watch(({ result }) => console.log(result));

rxjs 使用操作符处理异步流。

  • switchMap, mergeMap 等控制并发。
  • 适合处理取消请求或防抖。
// rxjs: 操作符处理
import { switchMap } from 'rxjs/operators';

inputChanges$.pipe(
  debounceTime(300),
  switchMap(val => api.search(val))
).subscribe(result => console.log(result));

⚛️ React 集成:Provider vs Observer vs Hooks

redux 需要 Provider 包裹应用。

  • 使用 useSelector 获取状态。
  • 使用 useDispatch 发送动作。
// 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。

  • 无需 Provider 包裹根组件。
  • 直接导入 store 即可订阅。
// effector: React 集成
import { useStore } from 'effector-react';

function Counter() {
  const count = useStore($count);
  return <button onClick={() => increment()}>{count}</button>;
}

rxjs 通常配合自定义 Hook 使用。

  • 需要手动订阅并更新本地状态。
  • 或使用专门库如 react-rxjs。
// 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>;
}

🤝 共同点:共享的核心概念

虽然实现方式不同,但这些库在解决数据流问题上有许多共通之处。

1. 🔄 响应式更新机制

  • 都支持数据变化后自动更新视图。
  • 避免手动操作 DOM 或强制刷新。
// 所有库都支持这种模式:数据变 -> 视图变
// Redux: dispatch -> reducer -> store -> view
// MobX: set property -> reaction -> view
// Effector: event -> store -> view
// RxJS: next -> subscribe -> view

2. 🧩 模块化支持

  • 都允许将状态拆分为多个部分。
  • 支持组合多个小存储为大应用。
// Redux: combineReducers
// MobX: 多个 Store 类实例
// Effector: 多个 createStore
// RxJS: 多个 Subject 组合

3. 🛠️ 开发工具支持

  • 都有浏览器扩展或调试工具。
  • 支持查看状态变化历史。
// Redux: Redux DevTools
// MobX: MobX DevTools
// Effector: Effector Inspector
// RxJS: RxJS DevTools (较少用)

4. 🌐 社区与生态

  • 都有成熟的社区支持和教程。
  • 能与主流框架(React, Vue, Angular)配合。
// 都有对应的框架绑定包
// react-redux, mobx-react-lite, effector-react, react-rxjs

📊 总结:关键差异对比

特性reduxmobxeffectorrxjs
数据可变性❌ 不可变✅ 可变❌ 不可变 (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 vs effector vs mobx vs rxjs

  • redux:

    选择 redux 如果你需要严格的可预测状态管理、时间旅行调试以及庞大的生态系统支持。配合 Redux Toolkit 使用,适合大型团队协作和企业级应用。

  • effector:

    选择 effector 如果你需要强大的类型推导、无需 Provider 的架构以及高性能的细粒度更新。适合对 TypeScript 支持要求高且希望减少样板代码的大型项目。

  • mobx:

    选择 mobx 如果你偏好面向对象的编程风格,希望用最少的代码实现响应式状态,且不介意魔法般的自动依赖追踪。适合快速迭代的中小型应用。

  • rxjs:

    选择 rxjs 如果你的应用涉及复杂的异步事件流、WebSocket 数据流或需要高级操作符来处理数据转换。适合实时数据面板或复杂交互场景。

redux的README

Redux Logo

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.

GitHub Workflow Status npm version npm downloads redux channel on discord

Installation

Create a React Redux App

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.

Documentation

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.

Learn Redux

Redux Essentials Tutorial

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.

Redux Fundamentals Tutorial

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.

Help and Discussion

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!

Before Proceeding Further

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:

  • You have reasonable amounts of data changing over time
  • You need a single source of truth for your state
  • You find that keeping all your state in a top-level component is no longer sufficient

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:

Basic Example

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.

Logo

You can find the official logo on GitHub.

Change Log

This project adheres to Semantic Versioning. Every release, along with the migration instructions, is documented on the GitHub Releases page.

License

MIT