跳至主内容
非官方测试版翻译

本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →

Redux 发展简史

2011:JS MVC 框架时代

早期的 JavaScript MVC 框架如 AngularJS、Ember 和 Backbone 都存在设计缺陷。AngularJS 试图强制分离模板中的"控制器",但没有任何机制阻止开发者在模板中直接编写类似 <div onClick="$ctrl.some.deeply.nested.field = 123"> 的代码。与此同时,Backbone 基于事件发射器架构 —— 模型(Models)、集合(Collections)和视图(Views)都能自主触发事件。模型可能发出 "change:firstName" 这类事件,视图会订阅这些事件。但问题是,_任何_代码都可以订阅这些事件并执行额外逻辑,进而可能触发_更多_事件。

这使得这些框架极难调试和维护。更新单个模型的某个字段可能触发数十个事件和应用各处的逻辑执行,任何模板都能随时修改状态,导致开发者无法预测状态更新后的具体行为。

2014:Flux 架构诞生

2012-2013 年 React 首次公开时,Facebook 内部已使用它近两年。他们遇到的核心问题是:多个独立的 UI 组件需要访问相同数据(如"未读通知数量"),但使用 Backbone 风格的代码难以保持这种逻辑的清晰性。

Facebook 最终提出了"Flux"模式:创建多个单例存储(Store),如 PostsStoreCommentsStore。每个存储实例向 Dispatcher 注册,触发存储更新的_唯一_方式是调用 Dispatcher.dispatch({type: "somethingHappened"})。这个普通对象被称为"action"。该设计让状态更新逻辑半集中化 —— 应用的任意部分不能直接改变状态,所有状态变更都可预测。

2014 年 Facebook 公布了"Flux 架构"概念,但未提供完整实现库。这促使 React 社区创建了_数十个_Flux 变体库。

2015:Redux 诞生

2015 年中,Dan Abramov 开始构建新的 Flux 变体库 Redux,初衷是为技术演讲演示"时间旅行调试"。该库采用 Flux 模式但融入了函数式编程原则:用可预测的 reducer 函数进行不可变更新,替代存储_实例_。这实现了状态时间回溯功能,也使代码更直白、可测试且易于理解。

Redux 在 2015 年发布后迅速取代了其他 Flux 变体库。它首先被 React 生态中的资深开发者采用,到 2016 年,业内普遍认为"使用 React 就必须搭配 Redux"。(这导致了许多不必要的过度使用!)

值得注意的是,当时 React 只有_旧版_ Context API,它基本无法正常传递_更新后_的值。虽然可以将事件发射器放入 Context 进行订阅,但它不能可靠传输普通数据。因此许多人选择 Redux,因为它_确实_能在整个应用中稳定传递更新值。

Dan 很早就说过:“Redux 并非旨在成为编写代码的最短途径——它的目标是使代码可预测且易于理解”。部分原因在于它提供了一种一致的模式(状态更新由 reducer 处理,因此你总是可以通过查看 reducer 逻辑来了解状态值可能是什么、可能的 action 有哪些,以及它们会引起哪些更新)。此外,它还将逻辑移出组件树,这样 UI 主要只是声明“发生了这件事”,而你的组件也会变得更简单。同时,以“纯函数”形式编写的代码(如 reducer 和 selector)更易于理解:参数输入,结果输出,无需关注其他内容。最后,Redux 的设计使得 Redux DevTools 成为可能,它可以显示所有已派发 action 的可读列表、action/state 包含的内容以及每个 action 引起的变化。

早期的 Redux 模式尤其充斥着大量样板代码。通常需要创建 actions/todos.jsreducers/todos.jsconstants/todos.js 文件,仅仅是为了定义一个 action 类型(const ADD_TODO = "ADD_TODO")、action 创建函数和 reducer 分支。你还必须手动使用展开运算符编写不可变更新,这很容易出错。人们确实在 Redux 中获取并缓存服务器状态,但这需要大量手动编写的代码:编写 thunk 函数来执行获取操作、用获取到的数据派发 action,以及在 reducer 中管理缓存状态。

尽管存在这些样板代码,Redux 仍然变得流行起来,但这始终是最大的痛点。

2017:生态系统的竞争

到 2017-18 年,情况发生了变化。社区中的许多人更关注“数据获取与缓存”而非“客户端状态管理”,此时我们见证了像 Apollo、React Query、SWR 和 Urql 这样的数据获取库的兴起。与此同时,的 React Context API 也发布了,它能够正确地将更新后的值沿组件树向下传递。

这意味着 Redux 不再像以前那样“必不可少”——现在有其他工具可以解决许多相同的问题,它们存在不同程度的重叠(而且通常代码量更少)。频繁出现的关于“样板代码”的抱怨也引起了 Redux 用户的担忧。

2019:Redux Toolkit

因此,在 2019 年,我们构建并发布了 Redux Toolkit(RTK),作为一种用更少代码编写相同 Redux 逻辑的更简单方式。RTK 仍然是“Redux”(单一 store,通过派发 action 触发 reducer 中基于不可变更新逻辑的状态更新),但具有更简单的 API 和更好的内置默认行为。其中还包括 RTK Query,这是我们受 React Query 和 Apollo 启发而开发的内置数据获取与缓存库。

如今,RTK 已成为编写 Redux 逻辑的标准方式。与所有工具一样,它也有权衡取舍。使用 RTK 可能需要比 Zustand 稍多的代码,但它也提供了将应用逻辑与 UI 分离的有用模式。Redux 并非适用于所有应用的正确工具,但它仍然是 React 应用中使用最广泛的状态管理库,拥有出色的文档,并提供了许多功能来帮助你构建具有一致且可预测结构的应用。

扩展阅读