🔄 Redux

一句话定性

2015 年,Dan Abramov 受 Flux 和 Elm 启发,做出 Redux:单一数据源 + 纯函数 reducer + 不可变更新,把状态变化变成一条可追溯、可重放、可时间旅行的事件流。它用极致的可预测性定义了一个时代,也用令人发指的样板代码逼出了它的所有反叛者。


一、它是什么 & 出现的时代

Redux 是一个可预测的状态容器,2015 年由 Dan Abramov(后加入 React 团队)和 Andrew Clark 创建,诞生于 2013-2018 SPA时代React 生态。

它的直接前身是 Facebook 2014 年提出的 Flux 架构(一种”数据只能单向流动”的思想),Redux 把 Flux 简化、并融入了 Elm 架构(函数式、不可变)的精髓。

一个著名的演示

Dan Abramov 在 React Europe 2015 上演示 Redux 的时间旅行调试(time-travel debugging)——把状态变化录下来、来回拖动重放——惊艳全场,Redux 一夜成名。


二、为什么会出现(解决上一代什么痛点)

Flux 之前的混乱

2013-2018 SPA时代的组件化带来跨组件状态共享难题(见 状态管理演进史)。早期的 MVC / 双向绑定下,数据流向是双向甚至网状的:模型改视图、视图改模型,改着改着就成了”谁也说不清现在的状态为什么是这样”。

Facebook 自己就被这个坑惨了(著名的”未读消息数对不上”bug)。Flux 给出的药方是:强制数据单向流动。Redux 进一步把它收敛到三条铁律。


三、核心机制 & 为什么流行

三大原则(Redux 的宪法)

  1. 单一数据源(Single Source of Truth):整个应用的状态存在一棵 state 树里,只有一个 store。
  2. 状态只读:不能直接改 state,唯一改变方式是 dispatch 一个 action(描述”发生了什么”的纯对象)。
  3. 用纯函数(reducer)做变更:(oldState, action) => newState,纯函数 + 不可变,相同输入永远得到相同输出。

单向数据流

   ┌──────────────────────────────────────────────┐
   │                                                │
   ▼                                                │
 View ──dispatch(action)──► Store ──► Reducer ──► new State
   ▲                                                │
   └───────────── 订阅,state 变就重渲染 ─────────────┘

数据只朝一个方向转圈,永远不会”反向偷偷改”

为什么流行

可预测性是它的全部魅力

  • 可追溯:每次变化都是一个有名字的 action,像一本”状态变更日志”。
  • 时间旅行调试:能录制 action 序列、回退、重放——debug 体验降维打击。
  • 可测试:reducer 是纯函数,测试不需要 mock 任何东西。
  • 生态强大:Redux DevTools、中间件(redux-thunk / redux-saga 处理异步)、与 React 的 react-redux 绑定。

四、带来的新问题 / 副作用

"为了改一个值,要写三个文件"

  1. 样板代码(boilerplate)爆炸:加一个功能要写 action type 常量、action creator、reducer case、再 dispatch、再 connect——改一个值的链路又长又啰嗦,这是 Redux 被诟病最多的一点。
  2. 不可变更新繁琐:手写 {...state, nested: {...state.nested, x: 1}} 这种深层展开,易错又难读。
  3. 异步是个痛点:reducer 必须纯,异步逻辑只能塞进中间件(thunk/saga),又是一层学习成本。
  4. 过度使用:很多小项目根本不需要全局 store,却跟风上 Redux,徒增复杂度(违背奥卡姆剃刀)。

这些副作用,直接催生了 MobX(响应式反样板)和 Zustand(极简反叛)。


五、现状 / 演化:Redux Toolkit 的救赎

RTK——Redux 官方的自我修正

面对”样板太多”的群嘲,Redux 团队推出 Redux Toolkit(RTK),成为官方推荐的标准写法:

  • createSlice 一次性生成 action + reducer,样板砍掉一大半
  • 内置 Immer,可以”看似直接修改”state(state.x = 1),底层自动转成不可变更新——消灭了手写展开运算符的痛苦
  • createAsyncThunkRTK Query(数据请求与缓存)把异步也收编了。

如今:大型、复杂、多人协作的企业级应用里,Redux(+ RTK)仍是最稳妥的选择——它的”啰嗦”在大团队里反而变成”清晰的约束”。但中小项目越来越多地转向 Zustand 等轻量方案。


六、对后续技术的影响(因果链)

 Flux(2014 单向数据流思想) + Elm(函数式/不可变)
                       │
                       ▼
                 Redux(2015, Dan Abramov)── 强绑定 [[React]]
                       │
   ┌───────────────────┼───────────────────────────┐
   ▼                   ▼                           ▼
 单一数据源          纯 reducer + 不可变           时间旅行调试
   │                   │                           │
   ▼                   ▼                           ▼
 可预测但样板多 ──┬──► [[MobX]] 反样板(响应式/可变)
                 │
                 ├──► [[Zustand]] 反叛(无 Provider/极简)
                 │
                 ├──► [[Vuex-Pinia\|Vuex]] 借鉴单向思想到 [[Vue]] 生态
                 │
                 └──► Redux Toolkit 自救(createSlice + Immer,砍样板)

历史地位

Redux 是状态管理史的奠基者和参照系:它确立了”单一数据源 + 单向数据流 + 不可变”这套至今仍是教科书级别的可预测性范式。它后来所有的”竞争对手”,本质上都是在回答同一个问题——“如何在不丢掉可预测性的前提下,把 Redux 的样板砍掉?” 它定义了整只 钟摆的一端。


🔗 相关:状态管理演进史 | MobX | Vuex-Pinia | Zustand | React | 2013-2018 SPA时代