Skip to main content

现有技术

¥Prior Art

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

¥Redux has a mixed heritage. It is similar to some patterns and technologies, but is also different from them in important ways. We'll explore some of the similarities and the differences below.

开发者经验

¥Developer Experience

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

¥Dan Abramov (author of Redux) wrote Redux while working on his React Europe talk called “Hot Reloading with Time Travel”. His goal was to create a state management library with a minimal API but completely predictable behavior. Redux makes it possible to implement logging, hot reloading, time travel, universal apps, record and replay, without any buy-in from the developer.

Dan 谈到了他在 更新日志第 187 集 中的一些意图和做法。

¥Dan talked about some of his intent and approach in Changelog episode 187.

影响

¥Influences

Redux 发展了 通量 的思想,但通过借鉴 榆树 的线索避免了其复杂性。即使你没有使用过 Flux 或 Elm,Redux 只需几分钟即可上手。

¥Redux evolves the ideas of Flux, but avoids its complexity by taking cues from Elm. Even if you haven't used Flux or Elm, Redux only takes a few minutes to get started with.

通量

¥Flux

Redux 的灵感来自于 通量 的几个重要品质。与 Flux 一样,Redux 要求你将模型更新逻辑集中在应用的某一层(Flux 中的“stores”,Redux 中的“reducers”)。两者都告诉你将每个突变描述为称为“操作”的普通对象,而不是让应用代码直接改变数据。

¥Redux was inspired by several important qualities of Flux. Like Flux, Redux prescribes that you concentrate your model update logic in a certain layer of your application (“stores” in Flux, “reducers” in Redux). Instead of letting the application code directly mutate the data, both tell you to describe every mutation as a plain object called an “action”.

与 Flux 不同,Redux 没有 Dispatcher 的概念。这是因为它依赖于纯函数而不是事件触发器,并且纯函数很容易组合并且不需要额外的实体来管理它们。根据你如何看待 Flux,你可能会将其视为偏差或实现细节。通量通常为 描述为 (state, action) => state。从这个意义上说,Redux 忠实于 Flux 架构,但由于纯函数而使其变得更简单。

¥Unlike Flux, Redux does not have the concept of a Dispatcher. This is because it relies on pure functions instead of event emitters, and pure functions are easy to compose and don't need an additional entity managing them. Depending on how you view Flux, you may see this as either a deviation or an implementation detail. Flux has often been described as (state, action) => state. In this sense, Redux is true to the Flux architecture, but makes it simpler thanks to pure functions.

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

¥Another important difference from Flux is that Redux assumes you never mutate your data. You can use plain objects and arrays for your state just fine, but mutating them inside the reducers is strongly discouraged. You should always return a new object, which can be done using the object spread operator or the Immer immutable update library.

虽然 编写不纯的 reducer 在技术上可以针对性能极端情况改变数据,但我们强烈建议你不要这样做。时间旅行、记录/重放或热重载等开发功能将被破坏。此外,在大多数实际应用中,不可变性似乎不会带来性能问题,因为,正如 Om 所演示的那样,即使你失去了对象分配,你仍然可以通过避免昂贵的重新渲染和重新计算而获胜,因为你确切地知道由于 reducer 纯度而发生了什么变化。

¥While it is technically possible to write impure reducers that mutate the data for performance corner cases, we actively discourage you from doing this. Development features like time travel, record/replay, or hot reloading will break. Moreover it doesn't seem like immutability poses performance problems in most real apps, because, as Om demonstrates, even if you lose out on object allocation, you still win by avoiding expensive re-renders and re-calculations, as you know exactly what changed thanks to reducer purity.

无论如何,Flux 的创造者是 approveRedux

¥For what it's worth, Flux's creators approve of Redux.

榆树

¥Elm

榆树 是一种受 Haskell 启发、由 埃文·恰普利茨基 创建的函数式编程语言。它强制执行 “模型视图更新”架构,其中更新具有以下签名:(action, state) => state。Elm“更新器”与 Redux 中的 reducer 具有相同的用途。

¥Elm is a functional programming language inspired by Haskell and created by Evan Czaplicki. It enforces a “model view update” architecture, where the update has the following signature: (action, state) => state. Elm “updaters” serve the same purpose as reducers in Redux.

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

¥Unlike Redux, Elm is a language, so it is able to benefit from many things like enforced purity, static typing, out of the box immutability, and pattern matching (using the case expression). Even if you don't plan to use Elm, you should read about the Elm architecture, and play with it. There is an interesting JavaScript library playground implementing similar ideas. We should look there for inspiration on Redux! One way that we can get closer to the static typing of Elm is by using a gradual typing solution like Flow.

不可变的

¥Immutable

不可变的 是一个实现持久数据结构的 JavaScript 库。它具有高性能并具有惯用的 JavaScript API。

¥Immutable is a JavaScript library implementing persistent data structures. It is performant and has an idiomatic JavaScript API.

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

¥(Note that while Immutable.js helped inspire Redux, today we recommend using Immer for immutable updates instead.)

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

¥Redux doesn't care how you store the state—it can be a plain object, an Immutable object, or anything else. You'll probably want a (de)serialization mechanism for writing universal apps and hydrating their state from the server, but other than that, you can use any data storage library as long as it supports immutability. For example, it doesn't make sense to use Backbone for Redux state, because Backbone models are mutable.

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

¥Note that, even if your immutable library supports cursors, you shouldn't use them in a Redux app. The whole state tree should be considered read-only, and you should use Redux for updating the state, and subscribing to the updates. Therefore writing via cursor doesn't make sense for Redux. If your only use case for cursors is decoupling the state tree from the UI tree and gradually refining the cursors, you should look at selectors instead. Selectors are composable getter functions. See reselect for a really great and concise implementation of composable selectors.

猴面包树

¥Baobab

猴面包树 是另一个流行的库,它实现了用于更新纯 JavaScript 对象的不可变 API。虽然你可以将其与 Redux 一起使用,但将它们一起使用几乎没有什么好处。

¥Baobab is another popular library implementing immutable API for updating plain JavaScript objects. While you can use it with Redux, there is little benefit in using them together.

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

¥Most of the functionality Baobab provides is related to updating the data with cursors, but Redux enforces that the only way to update the data is to dispatch an action. Therefore they solve the same problem differently, and don't complement each other.

与 Immutable 不同,Baobab 尚未在底层实现任何特殊的高效数据结构,因此将它与 Redux 一起使用并不会真正带来任何好处。在这种情况下,使用普通对象会更容易。

¥Unlike Immutable, Baobab doesn't yet implement any special efficient data structures under the hood, so you don't really win anything from using it together with Redux. It's easier to just use plain objects in this case.

接收 JS

¥RxJS

接收 JS 是管理异步应用复杂性的绝佳方法。事实上 人们正在努力创建一个库,将人机交互建模为相互依赖的可观察量

¥RxJS is a superb way to manage the complexity of asynchronous apps. In fact there is an effort to create a library that models human-computer interaction as interdependent observables.

将 Redux 与 RxJS 一起使用有意义吗?当然!他们合作得很好。例如,很容易将 Redux 存储公开为可观察对象:

¥Does it make sense to use Redux together with RxJS? Sure! They work great together. For example, it is easy to expose a Redux store as an observable:

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

同样,你可以组合不同的异步流,将它们转换为操作,然后再将它们提供给 store.dispatch()

¥Similarly, you can compose different asynchronous streams to turn them into actions before feeding them to store.dispatch().

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

¥The question is: do you really need Redux if you already use Rx? Maybe not. It's not hard to re-implement Redux in Rx. Some say it's a two-liner using Rx .scan() method. It may very well be!

如果你有疑问,请查看 Redux 源代码(那里没有太多内容)及其生态系统(例如 开发者工具)。如果你不太关心它并且想要一直使用反应式数据流,你可能想探索像 循环 这样的东西,甚至将它与 Redux 结合起来。让我们知道怎么回事!

¥If you're in doubt, check out the Redux source code (there isn't much going on there), as well as its ecosystem (for example, the developer tools). If you don't care too much about it and want to go with the reactive data flow all the way, you might want to explore something like Cycle instead, or even combine it with Redux. Let us know how it goes!

感言

¥Testimonials

“喜欢你用 Redux 所做的事情” Flux 创始人 Jing Chen

¥“Love what you're doing with Redux” Jing Chen, creator of Flux

“我在 FB 内部 JS 讨论组中征求了有关 Redux 的意见,得到了普遍好评。真的很棒的工作。” Bill Fisher,Flux 文档的作者

¥“I asked for comments on Redux in FB's internal JS discussion group, and it was universally praised. Really awesome work.” Bill Fisher, author of Flux documentation

“你根本不做 Flux 就发明了更好的 Flux,这真是太酷了。” 安德烈·斯塔尔茨(André Staltz),Cycle 创始人

¥“It's cool that you are inventing a better Flux by not doing Flux at all.” André Staltz, creator of Cycle

谢谢

¥Thanks

特别感谢 杰米佩顿 交出 redux NPM 包名。

¥Special thanks to Jamie Paton for handing over the redux NPM package name.

赞助人

¥Patrons

Redux 的最初工作是 由社区资助。认识一些使这一切成为可能的杰出公司:

¥The original work on Redux was funded by the community. Meet some of the outstanding companies that made it possible:

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

¥See the full list of original Redux patrons, as well as the always-growing list of people and companies that use Redux.