跳至主内容

操作(Actions)

非官方测试版翻译

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

Redux 常见问题:操作(Actions)

为什么 type 应该是字符串?为什么 action 类型应该是常量?

与状态(state)类似,可序列化的操作(actions)是 Redux 多个核心功能的基础,例如时间旅行调试(time travel debugging)以及操作的录制与回放。如果使用 Symbol 作为 type 值或对操作进行 instanceof 检查,会破坏这些功能。字符串具有可序列化和自描述性强的特点,因此是更优的选择。需要注意的是,如果操作是供中间件(middleware)使用的,则可以在其中使用 Symbols、Promises 或其他不可序列化的值。操作只需要在真正到达 store 并传递给 reducer 时具备可序列化性即可。

出于性能考虑,我们无法强制要求操作必须完全可序列化,因此 Redux 仅验证每个操作是否为普通对象且 type 是否为字符串。其余部分由开发者自行决定,但保持所有内容可序列化将有助于问题调试和复现。

封装和集中管理常用代码是编程的核心原则。虽然可以手动创建操作对象并逐一编写 type 值,但定义可复用的常量能显著提升代码可维护性。将常量放在独立文件中后,您还能通过工具检查 import 语句的拼写错误,避免意外使用错误的字符串。

扩展阅读

文档

讨论

reducer 和 action 之间总是一一对应吗?

并非如此。我们建议编写独立的小型 reducer 函数,每个函数仅负责特定状态片段的更新,这种模式称为 "reducer 组合"。一个 action 可能被所有、部分或零个 reducer 处理。这种设计使组件与实际数据变更解耦,因为单个 action 可能影响状态树的不同部分,而组件无需感知这些细节。虽然部分用户会选择更紧密的耦合方式(如 "ducks" 文件结构),但默认并不存在一一对应关系。当您需要在多个 reducer 中处理同一 action 时,完全可以突破这种范式限制。

扩展阅读

文档

讨论

如何表示 AJAX 调用等"副作用"?为什么需要"action creators"、"thunks"和"middleware"来处理异步行为?

这是一个复杂且存在多种观点的话题,不同开发者对代码组织方式和实现异步逻辑的最佳实践各有见解。

任何有实际意义的 Web 应用都需要执行复杂逻辑,通常包含 AJAX 请求等异步操作。这类代码不再纯粹依赖于输入参数,与外部环境的交互被称为“副作用”

Redux 受函数式编程启发,其核心设计并不包含执行副作用的机制。特别需要注意的是,reducer 函数必须是纯函数,遵循 (state, action) => newState 的模式。然而,Redux 的中间件机制可以拦截分发的 action,并围绕它们添加包含副作用的复杂行为。

通常,Redux 建议将包含副作用的逻辑放在 action 创建过程中。虽然这些逻辑可以在 UI 组件内实现,但将其提取为可复用的函数(即 action creator)更为合理,这样相同逻辑就能在多个位置调用。

最简单常见的解决方案是使用 Redux Thunk 中间件,它允许你编写包含复杂异步逻辑的 action creator。另一个流行方案是 Redux Saga,通过生成器(generator)编写类同步代码,在 Redux 应用中扮演"后台线程"角色。还有 Redux Loop 采用反转控制模式,允许 reducer 声明状态变化触发的副作用。此外,社区还提供了众多各具特色的解决方案。

扩展阅读

文档

文章

讨论

应该使用哪种异步中间件?如何在 thunks、sagas、observables 或其他方式之间做出选择?

许多可用的异步/副作用中间件,但最常用的是 redux-thunkredux-sagaredux-observable。这些是不同的工具,各有其优势、劣势和适用场景。

根据经验法则:

  • Thunks 最适合处理复杂的同步逻辑(尤其是需要访问整个 Redux 存储状态的代码)和简单的异步逻辑(如基本的 AJAX 调用)。结合使用 async/await 时,thunks 也能合理处理更复杂的基于 Promise 的逻辑。

  • Sagas 最适合处理复杂的异步逻辑和分离的"后台线程"类型行为,特别是当你需要监听已分发的 action(这是 thunks 无法做到的)。它们要求熟悉生成器函数和 redux-saga 的"effects"操作符。

  • Observables 解决与 sagas 相同的问题,但依赖于 RxJS 来实现异步行为。它们要求熟悉 RxJS API。

我们建议大多数 Redux 用户从 thunks 开始,如果应用确实需要处理更复杂的异步逻辑,再添加额外的副作用库如 sagas 或 observables。

由于 sagas 和 observables 的用例相同,应用通常只会使用其中之一,而不是两者都用。但请注意,同时使用 thunks 和 sagas 或 observables 是完全可以的,因为它们解决不同的问题。

文章

讨论

是否应该在一个 action creator 中连续分发多个 action?

action 的结构设计没有硬性规定。使用像 Redux Thunk 这样的异步中间件确实支持多种场景,例如连续分发多个独立但相关的 action、分发表示 AJAX 请求进度的 action、根据状态有条件地分发 action,甚至分发 action 后立即检查更新后的状态。

通常需要判断这些 action 是相关但独立的,还是应该合并为单个 action。选择适合你具体场景的方案,但要权衡 reducer 的可读性与 action 日志的可读性。例如,包含完整新状态树的 action 可以让 reducer 简化为单行代码,但缺点是失去了变更原因的追溯记录,导致调试困难。反之,如果循环分发多个细粒度 action,则表明可能需要引入新的 action 类型并以不同方式处理。

在性能敏感场景中,应避免连续同步分发多次 action。有多种插件和方法可以实现 action 的批量分发。

扩展阅读

文档

文章

讨论