菜单

高级 React-Redux 模式

相关源文件

本页介绍了有效使用 React 与 Redux 的高级模式和技术。它着重于优化性能、正确组织组件、处理复杂数据流以及实现复杂的状态管理解决方案。有关基本的 React-Redux 集成和 Hooks 用法,请参阅React-Redux Hooks

组件优化模式

React-Redux 应用程序经常面临性能挑战,当组件不必要地重新渲染或复杂状态派生导致瓶颈时,尤为突出。以下是解决这些问题的模式。

记忆化选择器

Redux 中最重要的模式之一是使用记忆化选择器高效地从 store 中派生数据。虽然基本选择器适用于简单的状态访问,但记忆化选择器可以在底层数据未发生变化时防止不必要的重复计算。

记忆化选择器的主要优点包括

  1. 性能优化:仅当输入发生变化时才执行计算
  2. 派生数据缓存:复杂的转换会被缓存,直到需要时才重新计算
  3. 组件隔离:组件无需了解状态结构

来源:docs/tutorials/essentials/part-6-performance-normalization.md65-134 docs/tutorials/fundamentals/part-7-standard-patterns.md62-120

选择性组件渲染

与其让一个连接组件传递大量 props,不如将多个组件连接到 store,让它们在需要时访问特定的状态片段。

关键实现技术

  1. 使用 useSelector 只拉取组件所需数据
  2. 对纯函数组件实现 React.memo()
  3. 确保选择器返回一致的引用

来源:docs/faq/ReactRedux.md62-125 docs/tutorials/fundamentals/part-5-ui-and-react.md137-200

处理异步逻辑

Redux thunk 是处理异步操作的标准方式,但有效地组织此代码需要特定的模式。

请求状态管理

使用枚举风格的方法,通过专门的状态字段跟踪加载状态

这种模式包括

  1. 向相关的状态切片添加状态字段
  2. 在状态旁边跟踪错误
  3. 使 UI 组件响应这些状态值

来源:docs/tutorials/essentials/part-5-async-logic.md295-338 docs/tutorials/fundamentals/part-7-standard-patterns.md211-289

用于数据获取的 Thunk 模式

Thunk 提供了一种使用 Redux 处理异步操作的一致方式

重要的 thunk 模式包括

  1. 分发用于请求状态的“pending/fulfilled/rejected”action
  2. 结合 createAppAsyncThunk 使用类型安全
  3. 实现请求条件检查以避免重复请求
  4. 在 UI 组件中处理加载状态

来源:docs/tutorials/essentials/part-5-async-logic.md89-141 docs/tutorials/essentials/part-5-async-logic.md405-450

规范化状态结构

复杂的应用程序需要高效的数据处理。规范化状态提供了一种模仿数据库表结构的解决方案。

实体规范化模式

规范化状态的优点

  1. 高效查找:通过 ID
  2. 无重复:实体数据不重复
  3. 更容易更新:单个项目
  4. 可预测的状态结构:适用于复杂数据

来源:docs/tutorials/fundamentals/part-7-standard-patterns.md386-471 docs/tutorials/essentials/part-6-performance-normalization.md200-350

高级选择器策略

选择器在组件和状态结构之间创建了一个抽象层,从而实现灵活的状态演变。

组合选择器

重要的选择器模式

  1. 首先构建简单选择器,然后组合它们
  2. 使用 createSelector 对耗时计算进行记忆化
  3. 参数化选择器用于过滤和排序
  4. 将选择器与相关 reducer 逻辑共同存放

来源:docs/tutorials/essentials/part-4-using-data.md445-486 docs/tutorials/essentials/part-6-performance-normalization.md65-84

高级 React-Redux 通信

复杂的应用程序需要超越简单状态更新的通信。这些模式有助于管理复杂的交互。

Redux Action 监听器

对于需要在不修改状态的情况下响应 action 的副作用,请使用监听器中间件

使用 Redux Toolkit 监听器中间件实现

  1. 使用 createListenerMiddleware 创建监听器中间件
  2. 使用 startAppListening 添加 effect 监听器
  3. 将副作用与状态更新分离

来源:docs/tutorials/essentials/part-6-performance-normalization.md571-650

组件到 Store 的通信模式

优化组件到 store 的通信

  1. 为每次交互使用适当的抽象
  2. 通过良好定义的 action creator 分发 action
  3. 在 thunk 中封装异步逻辑
  4. 将复杂的状态选择提取到记忆化选择器中

来源:docs/tutorials/essentials/part-5-async-logic.md525-587 docs/tutorials/fundamentals/part-5-ui-and-react.md200-275

使用 RTK Query 进行数据管理

对于高级数据获取模式,RTK Query 提供了一个全面的解决方案,它消除了与数据获取 thunk 相关的大部分样板代码。

使用标签进行缓存失效

关键的 RTK Query 模式

  1. 定义标签以表示数据中的实体
  2. 从查询端点提供标签
  3. 通过 mutations 使标签失效以触发重新获取
  4. 使用带有 ID 的特定标签进行定向失效

来源:docs/tutorials/essentials/part-8-rtk-query-advanced.md155-236 docs/tutorials/essentials/part-7-rtk-query-basics.md155-184

乐观 UI 更新

为了实现响应式界面,实现乐观更新,在服务器确认之前立即显示更改。

实现技术

  1. 在用户操作时立即更新 UI 状态
  2. 跟踪操作的“pending”状态
  3. 为失败情况准备回滚数据
  4. 通过 UI 反馈优雅地处理错误情况

来源:docs/tutorials/essentials/part-8-rtk-query-advanced.md240-310

项目结构的最佳实践

有效地组织 Redux 代码有助于维护大型应用程序。推荐的方法是采用基于功能的结构,其中“slice”定义自己的 action 和 reducer。

关键组织模式

  1. 按功能域而非功能类型对代码进行分组
  2. 在 slice 文件中共同存放 reducer、action 和 selector
  3. 导出类型化的 Hooks 供 React 组件使用
  4. 将 UI 组件与其相关的状态逻辑紧密放置

来源:docs/faq/CodeStructure.md30-57 docs/tutorials/essentials/part-2-app-structure.md172-194

类型安全模式

有效地将 TypeScript 与 Redux 结合使用可以改善开发者体验并防止常见错误。

Redux 类型化模式

重要的类型化模式

  1. 定义 store 类型一次,然后在整个应用程序中引用它们
  2. 创建 Hooks 和函数的预类型化版本
  3. 在 slice 文件中显式地为状态形状定义类型
  4. 使用 PayloadAction<T> 为 action payload 定义类型

来源:docs/tutorials/essentials/part-3-data-flow.md232-251 docs/tutorials/essentials/part-5-async-logic.md226-264

测试 Redux 应用程序涉及 Redux 架构不同部分的多种模式。

关键测试方法

  1. 将 reducer 作为纯函数进行测试,使用示例 action
  2. 使用准备好的状态对象测试选择器
  3. 测试 thunk 时模拟 API 调用
  4. 对连接组件使用集成测试

来源:docs/tutorials/fundamentals/part-7-standard-patterns.md590-650

结论

这些高级模式有助于构建可扩展和可维护的 Redux 应用程序。随着应用程序复杂性的增长,这些模式对于有效管理状态、优化性能和创造流畅的用户体验变得越来越重要。

此处概述的模式代表了多年来在生产应用程序中使用 Redux 而演变出的最佳实践。然而,您应始终根据您的具体应用程序需求调整这些模式,而非教条式地应用它们。

来源:docs/tutorials/essentials/part-6-performance-normalization.md1-50 docs/faq/CodeStructure.md1-62