Prior Art: Influences on the design of Redux">Prior Art: Influences on the design of Redux">
跳至主要内容

现有技术

Redux 拥有混合的传承。它与某些模式和技术类似,但在重要方面也与它们不同。我们将在下面探讨一些相似之处和不同之处。

开发者体验

Dan Abramov(Redux 的作者)在为他的 React Europe 演讲“热重载与时间旅行”准备时编写了 Redux。他的目标是创建一个具有最小 API 但行为完全可预测的状态管理库。Redux 使得能够实现日志记录、热重载、时间旅行、通用应用程序、记录和重放,而无需开发人员的任何投入。

Dan 在 Changelog 第 187 集 中谈论了他的一些意图和方法。

影响

Redux 发展了 Flux 的理念,但通过借鉴 Elm 来避免其复杂性。即使您没有使用过 Flux 或 Elm,Redux 也只需要几分钟就能上手。

Flux

Redux 的灵感来自 Flux 的几个重要特性。与 Flux 一样,Redux 规定您将模型更新逻辑集中在应用程序的特定层(Flux 中的“存储”,Redux 中的“reducers”)。两者都告诉您不要让应用程序代码直接修改数据,而是将每个修改描述为一个名为“action”的普通对象。

与 Flux 不同,Redux 没有 Dispatcher 的概念。这是因为它依赖于纯函数而不是事件发射器,而纯函数易于组合,不需要额外的实体来管理它们。根据您对 Flux 的看法,您可能会认为这是一种偏差或一种实现细节。Flux 经常被 描述为 (state, action) => state。从这个意义上说,Redux 忠实于 Flux 架构,但由于纯函数使其更简单。

与 Flux 的另一个重要区别是,Redux 假设您永远不会修改数据。您可以使用普通对象和数组作为您的状态,但强烈建议不要在 reducers 中修改它们。您应该始终返回一个新对象,这可以使用对象展开运算符或 Immer 不可变更新库 来完成。

虽然从技术上讲,您可以 编写修改数据的非纯 reducers 来处理性能方面的特殊情况,但我们强烈建议您不要这样做。像时间旅行、记录/回放或热重载这样的开发功能将会失效。此外,不可变性似乎在大多数实际应用程序中不会造成性能问题,因为正如 Om 所示,即使您失去了对象分配,您仍然可以通过避免昂贵的重新渲染和重新计算来获益,因为您确切地知道发生了什么变化,这得益于 reducer 的纯度。

值得一提的是,Flux 的创建者 赞成 Redux

Elm

Elm 是一种受 Haskell 启发的函数式编程语言,由 Evan Czaplicki 创建。它强制执行 “模型视图更新”架构,其中更新具有以下签名:(action, state) => state。Elm 的“更新器”与 Redux 中的 reducer 具有相同的目的。

与 Redux 不同,Elm 是一种语言,因此它能够从许多方面受益,例如强制纯度、静态类型、开箱即用的不可变性以及模式匹配(使用 case 表达式)。即使您不打算使用 Elm,也应该了解 Elm 架构并尝试一下。有一个有趣的 JavaScript 库游乐场实现了类似的想法。我们应该从那里寻找 Redux 的灵感!我们可以更接近 Elm 静态类型的一种方法是 使用像 Flow 这样的渐进式类型解决方案

不可变

Immutable 是一个实现持久数据结构的 JavaScript 库。它性能出色,并具有惯用的 JavaScript API。

(请注意,虽然 Immutable.js 帮助启发了 Redux,但今天我们建议 使用 Immer 来进行不可变更新。)

Redux 不关心您如何存储状态——它可以是普通对象、Immutable 对象或任何其他东西。您可能需要一个(反)序列化机制来编写通用应用程序并从服务器加载其状态,但除此之外,您可以使用任何数据存储库只要它支持不可变性。例如,使用 Backbone 作为 Redux 状态没有意义,因为 Backbone 模型是可变的。

请注意,即使您的不可变库支持游标,您也不应该在 Redux 应用程序中使用它们。整个状态树应被视为只读,您应该使用 Redux 来更新状态并订阅更新。因此,通过游标写入对 Redux 没有意义。如果您使用游标的唯一用例是将状态树与 UI 树解耦并逐步细化游标,那么您应该考虑使用选择器。选择器是可组合的获取器函数。有关可组合选择器的出色且简洁的实现,请参见 reselect

Baobab

Baobab 是另一个流行的库,它实现了用于更新普通 JavaScript 对象的不可变 API。虽然你可以在 Redux 中使用它,但将它们一起使用并没有什么好处。

Baobab 提供的大部分功能都与使用游标更新数据有关,但 Redux 强制规定更新数据的唯一方法是分派操作。因此,它们以不同的方式解决相同的问题,并且不会相互补充。

与 Immutable 不同,Baobab 尚未在幕后实现任何特殊的有效数据结构,因此你实际上不会从将它与 Redux 一起使用中获得任何好处。在这种情况下,直接使用普通对象更容易。

RxJS

RxJS 是管理异步应用程序复杂性的绝佳方法。事实上,有人正在努力创建一个库,将人机交互建模为相互依赖的可观察对象

将 Redux 与 RxJS 一起使用有意义吗?当然!它们可以很好地协同工作。例如,很容易将 Redux 存储公开为可观察对象

function toObservable(store) {
return {
subscribe({ next }) {
const unsubscribe = store.subscribe(() => next(store.getState()))
next(store.getState())
return { unsubscribe }
}
}
}

类似地,你可以组合不同的异步流,将它们转换为操作,然后将它们馈送到 store.dispatch()

问题是:如果你已经使用 Rx,你真的需要 Redux 吗?也许不需要。用 Rx 的 .scan() 方法重新实现 Redux 并不难。有些人说这只需要两行代码。很有可能!

如果你有疑问,请查看 Redux 源代码(那里没有太多内容),以及它的生态系统(例如,开发者工具)。如果你不太关心它,并且想一直使用响应式数据流,你可能想探索类似于 Cycle 的东西,甚至将其与 Redux 结合使用。请告诉我们结果如何!

推荐

“我喜欢你对 Redux 的工作” Jing Chen,Flux 的创建者

“我在 Facebook 内部 JS 讨论组中询问了关于 Redux 的意见,它得到了普遍赞扬。非常棒的工作。” Bill Fisher,Flux 文档作者

“不使用 Flux,却创造了一个更好的 Flux,这很酷。” André Staltz,Cycle 的创造者

感谢

  • Elm 架构,它为使用 reducer 对状态更新建模提供了很好的入门介绍;
  • 将数据库翻转过来,让我大开眼界;
  • 使用 Figwheel 开发 ClojureScript,说服我重新评估应该“正常工作”;
  • Webpack,用于热模块替换;
  • Flummox,教会我如何不使用样板代码或单例来使用 Flux;
  • disto,用于热加载存储的概念验证;
  • NuclearJS,证明这种架构可以具有高性能;
  • Om,推广了单个状态原子的概念;
  • Cycle,展示了函数在很多情况下都是最佳工具;
  • React,用于务实的创新。

特别感谢 Jamie Paton 交出 redux NPM 包名称。

赞助商

Redux 的最初工作是由 社区资助的。认识一下让这一切成为可能的优秀公司

查看完整的 Redux 赞助商列表,以及不断增长的 使用 Redux 的个人和公司列表