菜单

Redux 与 React

相关源文件

本文档解释了如何使用官方的 React-Redux 库将 Redux 集成到 React 应用程序中。它涵盖了将 Redux store 连接到 React 组件的核心模式、实现此功能的基本 API 以及常见的使用模式。有关 Redux 本身的信息,请参阅Redux 概述;有关高级 Redux 模式,请参阅高级用法

介绍

Redux 是一个状态管理库,可以与任何 UI 层协同工作。React-Redux 是 Redux 官方的 React UI 绑定库,提供了专门为在 React 应用程序中与 Redux 配合使用而设计的组件和 Hook。

虽然可以在不使用 React-Redux 的情况下直接在 React 中使用 Redux,但 React-Redux 库提供了优化的方法来将 Redux 连接到您的 React 组件,使开发更高效、性能更好。

来源:[docs/tutorials/fundamentals/part-5-ui-and-react.md:32-39, 92-100], [docs/faq/ReactRedux.md:30-42]

核心概念

Redux 和 UI 的基本集成

当 Redux 与任何 UI 层(包括 React)一起使用时,集成遵循以下步骤

  1. 创建 Redux store
  2. 订阅更新
  3. 在订阅回调中
    • 获取当前 store 状态
    • 提取 UI 所需的数据
    • 用数据更新 UI
  4. 使用初始状态渲染 UI
  5. 通过 dispatch Redux action 响应 UI 输入

React-Redux 为我们处理这些步骤,因此我们无需手动编写此逻辑。

来源:[docs/tutorials/fundamentals/part-5-ui-and-react.md:43-87]

Provider 组件

来自 React-Redux 的 Provider 组件使 Redux store 对应用程序中的所有 React 组件可用。它应该包装您的整个应用程序,通常在根级别。

Provider 组件使用 React 的上下文功能,使得需要使用 React-Redux Hook 与 Redux store 交互的任何嵌套组件都能访问 Redux store。

来源:[docs/tutorials/fundamentals/part-5-ui-and-react.md:279-310]

React-Redux Hooks

React-Redux 提供了多个用于与 Redux store 交互的 Hook

useSelector

useSelector Hook 允许组件从 Redux store 状态中提取数据

useSelector Hook

  • 接受一个 selector 函数,该函数以整个 Redux 状态作为其参数
  • 返回 selector 函数返回的任何值
  • 将组件订阅到 Redux store
  • 当 action 被 dispatch 时重新运行 selector
  • 如果选定的值发生变化,则导致组件重新渲染

来源:[docs/tutorials/fundamentals/part-5-ui-and-react.md:134-226]

useDispatch

useDispatch Hook 允许组件访问 Redux store 的 dispatch 方法

通过 useDispatch,React 组件可以 dispatch action 来更新 Redux store。

来源:[docs/tutorials/fundamentals/part-5-ui-and-react.md:227-277]

React 和 Redux 之间的数据流

此图说明了如何使用 React-Redux 在 React 组件和 Redux store 之间进行数据流转

来源:[docs/tutorials/fundamentals/part-5-ui-and-react.md:134-226, 227-277], [docs/tutorials/fundamentals/part-1-overview.md:265-307]

常见模式和最佳实践

全局状态与组件状态

并非所有应用程序状态都需要保存在 Redux 中。局部组件状态仍然适用于:

  • 仅与特定组件相关的 UI 状态
  • 表单编辑期间的表单输入值
  • 临时 UI 状态,例如工具提示可见性

在决定在哪里存储状态时,请考虑以下准则

  • 对于组件之间共享的状态,请使用 Redux
  • 对于需要在组件生命周期中持久化的状态,请使用 Redux
  • 对于 UI 特定的关注点,请使用局部组件状态

来源:[docs/tutorials/fundamentals/part-5-ui-and-react.md:331-359], [docs/faq/OrganizingState.md:25-39]

使用 Selector 的组件设计

在组件中使用多个 Selector

组件可以多次调用 useSelector 来提取不同的状态片段

这种方法有助于组件只访问它们所需的数据。

来源:[docs/tutorials/fundamentals/part-5-ui-and-react.md:360-418]

按 ID 选择项目

为了优化列表渲染,一个常见的模式是让父组件选择一个 ID 数组,而子组件则根据 ID 选择自己的数据。

当只有一个项目发生变化时,这种模式可以避免列表项不必要的重新渲染。

来源:[docs/tutorials/fundamentals/part-5-ui-and-react.md:420-534]

性能优化

useSelector 中的相等性比较

默认情况下,useSelector 使用严格的 === 引用相等性检查。当您的 selector 每次返回新引用时(例如新数组或对象),这可能会导致不必要的重新渲染。

使用 React-Redux 中的 shallowEqual 函数作为 useSelector 的第二个参数来比较对象。

来源:[docs/tutorials/fundamentals/part-5-ui-and-react.md:505-533], [docs/faq/ReactRedux.md:85-120]

记忆化 Selector

对于复杂的数据转换,使用记忆化 selector 来提高性能。reselect 库常用于此。

记忆化 selector 仅在其输入发生变化时重新计算,避免了每次渲染时昂贵的操作。

来源:[docs/tutorials/fundamentals/part-7-standard-patterns.md], [docs/faq/ReactRedux.md:125-142]

代码结构和组织

组件组织

Redux 与不同的 React 组件组织策略配合良好

您可以灵活地

  • 仅连接顶层组件并将数据向下传递
  • 连接组件树不同级别的多个组件
  • 根据您的需求混合连接和未连接的组件

来源:[docs/faq/ReactRedux.md:149-174], [docs/faq/CodeStructure.md:19-61]

常见文件夹结构

一个典型的 Redux 和 React 应用程序结构可能如下所示

src/
├── index.js           # Entry point with Provider setup
├── App.js             # Root component
├── store.js           # Store configuration
├── features/          # Feature-based organization
│   ├── todos/         # Todo feature
│   │   ├── todosSlice.js  # Redux logic (actions, reducers)
│   │   ├── TodoList.js    # Connected component
│   │   └── TodoItem.js    # Child component
│   └── filters/       # Filters feature
│       ├── filtersSlice.js # Redux logic
│       └── FilterControls.js # Connected component

这种结构按功能组织代码,将相关的 Redux 逻辑和 React 组件放在一起。

来源:[docs/faq/CodeStructure.md:35-56]

React-Redux 与 TypeScript

现代 Redux 应用程序通常使用 TypeScript 以确保类型安全。React-Redux 提供了有助于以下方面的类型定义:

  • 为 Redux store 状态提供类型
  • 为 selector、action 和 dispatch 提供类型
  • 确保正确的类型在应用程序中传递

来源:[docs/faq/ReactRedux.md]

与其他方法的比较

React-Redux 与直接 Store 使用

虽然可以在 React 组件中直接使用 Redux store,但 React-Redux 提供了显著的优势

  1. 性能优化 - React-Redux 实现了 shouldComponentUpdate,防止不必要的重新渲染
  2. 关注点分离 - 组件不需要了解 Redux 的实现细节
  3. 一致性 - 访问应用程序中状态的统一模式
  4. 测试 - 使用 React-Redux 的组件更容易进行独立测试

来源:[docs/faq/ReactRedux.md:31-44]

React-Redux 与 React Context API

虽然 React 的 Context API 也提供了一种在组件之间共享状态的方式,但 Redux 和 React-Redux 提供了额外的优势

  • 用于处理副作用的更强大的中间件
  • 用于调试的 DevTools
  • 时间旅行调试
  • 通过 reducer 更可预测的状态更新
  • 大型应用程序的更好性能

对于更简单的应用程序,Context API 可能就足够了,但 Redux 为复杂应用程序提供了更完整的状态管理解决方案。

来源:[docs/faq/ReactRedux.md:172-204], [docs/faq/General.md:36-70]

实际应用中的常见模式

将 Redux 与 React Router 结合使用

Redux 可以与 React Router 一起使用,路由更改可能会 dispatch action 来更新 store

来源:[examples/real-world/package.json:12-21]

处理异步逻辑

在使用 React 和 Redux 时,API 调用等异步操作通常使用 Redux Thunk 等中间件处理

React 组件可以 dispatch thunk action,它将处理异步流程并在适当时候 dispatch 常规 action。

来源:[docs/tutorials/fundamentals/part-6-async-logic.md:174-216], [examples/async/package.json:12-15]

故障排除

React-Redux 常见问题

  • 组件未更新:通常是由于直接修改状态而不是创建新对象/数组引起的
  • 过多重新渲染:可能是由于 selector 返回了新的对象引用引起的
  • 缺少 dispatch:发生在将 mapDispatchToProps 提供给 connect 但未返回 dispatch 时
  • 性能问题:通常通过实施适当的记忆化策略来解决

来源:[docs/faq/ReactRedux.md:51-84], [docs/faq/ReactRedux.md:85-120]

结论

React-Redux 提供了 Redux 可预测的状态容器与 React 组件系统之间的连接。通过遵循本文档中概述的模式,您可以构建具有组织良好状态管理的 React 应用程序,这些应用程序可以扩展到复杂的用例,同时保持性能和开发者体验。

请记住以下要点

  • 使用 <Provider> 使您的 store 对组件可用
  • 使用 useSelector 从 store 中读取数据
  • 使用 useDispatch dispatch action
  • 考虑哪些状态属于 Redux,哪些属于组件状态
  • 为大型应用程序使用性能优化技术

来源:[docs/tutorials/fundamentals/part-5-ui-and-react.md:535-579]