跳至主内容

Redux 基础教程,第一部分:Redux 概述

非官方测试版翻译

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

学习目标
  • 理解 Redux 是什么及其适用场景
  • 掌握构成 Redux 应用的核心要素

简介

欢迎来到 Redux 基础教程!本教程将介绍 Redux 的核心概念、原则和使用模式。完成学习后,您将理解构成 Redux 应用的各个模块、数据在 Redux 中的流动方式,以及我们推荐的 Redux 应用构建标准模式。

在本教程第一部分,我们将简要分析一个最小化的 Redux 应用示例,了解其组成部分;在第二部分:Redux 概念与数据流中,我们将深入探讨这些模块及其在 Redux 应用中的数据流动机制。

第三部分:状态、Action 和 Reducer开始,我们将运用这些知识构建小型示例应用,演示各模块如何协同工作,并讲解 Redux 的实际运作原理。在完整构建这个"手工实现"的示例应用后(以便您清晰理解每个细节),我们将讨论 Redux 常用的标准模式和抽象方案。最后,我们将展示这些基础示例如何转化为实际应用中推荐的高级模式。

如何阅读本教程

本教程将教会您 "Redux 的工作原理",同时阐释这些模式存在的深层原因。

非官方测试版翻译

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

注意

请注意,本教程有意展示旧式的 Redux 逻辑模式(这些模式比我们当前推荐的 "现代 Redux" 模式需要编写更多代码),目的是为了解释 Redux 背后的原理和概念。它_并非_用于生产环境的项目。

学习使用 Redux Toolkit 实现 "现代 Redux" 模式,请参考以下文档:

在您理解各模块的协作机制后,我们将介绍如何使用 Redux Toolkit 简化开发流程。Redux Toolkit 是构建生产级 Redux 应用的推荐方案,其设计基于本教程涵盖的所有核心概念。掌握这些基础概念后,您将能更高效地运用 Redux Toolkit。

我们力求以初学者友好的方式进行讲解,但仍需预设某些知识基础以便聚焦 Redux 核心原理。本教程假定您已掌握

前置知识

若你对这些主题尚未熟悉,建议先花时间掌握它们,再回来学习 Redux。我们随时在此等候!

最后,请确保浏览器已安装 React 和 Redux 开发者工具扩展:

什么是 Redux?

首先需要理解 "Redux" 究竟是什么。它能做什么?解决哪些问题?为何需要使用它?

Redux 是一种用于管理和更新全局应用状态的模式和库,其机制是:UI 触发称为 "actions" 的事件来描述发生了什么,而称为 "reducers" 的独立更新逻辑则响应这些事件来更新状态。 它作为集中存储库,管理需要在整个应用中共享的状态,并通过规则确保状态只能以可预测的方式更新。

为何应该使用 Redux?

Redux 帮助你管理 "全局" 状态——即应用中多个部分需要共享的状态。

Redux 提供的模式和工具让你更轻松地理解应用状态在何时、何地、为何及如何被更新,以及状态变更时应用逻辑将如何响应。Redux 引导你编写可预测且可测试的代码,从而确保应用按预期运行。

何时应该使用 Redux?

Redux 能协助管理共享状态,但如同任何工具,它存在权衡取舍。需要学习更多概念,编写更多代码。它还会增加代码的间接性,并要求遵循特定约束。这是在短期生产力与长期生产力之间的权衡。

Redux 在以下场景更为适用:

  • 应用中有大量状态需要在多个地方使用

  • 应用状态随时间频繁更新

  • 状态更新逻辑可能较为复杂

  • 应用代码库规模中等或庞大,且可能由多人协作开发

并非所有应用都需要 Redux。请仔细评估您构建的应用类型,确定哪些工具最适合解决当前问题。

扩展阅读

Redux 库与工具

Redux 本身是独立的小型 JS 库,但通常需配合以下包使用:

Redux Toolkit

Redux Toolkit 是我们推荐的 Redux 逻辑编写方案。它包含构建 Redux 应用必需的工具包和函数,内置最佳实践建议,能简化多数 Redux 任务,避免常见错误,并提升开发效率。

React-Redux

Redux 可与任何 UI 框架集成,最常与 React 搭配使用。React-Redux 是我们的官方包,让 React 组件能通过读取状态片段和派发 action 来与 Redux store 交互。

Redux DevTools 扩展

Redux DevTools 扩展 可展示 Redux store 中状态随时间的变化历史。这使您能高效调试应用,包括使用强大的"时间旅行调试"等技术。

Redux 基础

了解 Redux 是什么后,让我们简要解析构成 Redux 应用的模块及其运作机制。

信息

本页剩余内容聚焦于 Redux 核心库(即 redux 包)。其他相关包将在后续教程中逐步介绍。

Redux Store

每个 Redux 应用的核心是 store。Store 是存储应用全局状态的容器。

Store 是具有特殊功能的 JS 对象,使其区别于普通全局对象:

  • 你绝不应直接修改 Redux store 内部保存的状态

  • 相反,更新状态的唯一方式是创建一个描述"应用中发生事件"的普通 action 对象,然后将该 action 派发(dispatch) 到 store

  • 当 action 被派发后,store 会运行根 reducer 函数,该函数基于旧状态和 action 计算新状态

  • 最后,store 会通知 订阅者(subscribers) 状态已更新,以便 UI 能用新数据刷新

Redux 核心示例应用

让我们看一个 Redux 应用的最小工作示例——一个简单的计数器应用:

由于 Redux 是无依赖的独立 JS 库,本示例仅通过加载 Redux 库的单个 script 标签实现,UI 使用基础 JS 和 HTML 构建。实际开发中,Redux 通常通过 从 NPM 安装 Redux 包 使用,UI 则采用 React 等库构建。

信息

第五部分:UI 与 React 将展示如何结合使用 Redux 和 React。

我们将此示例拆解为独立部分,逐一分析其运行机制:

状态、Actions 和 Reducers

首先定义初始 状态 值来描述应用:

// Define an initial state value for the app
const initialState = {
value: 0
}

本应用中,我们将追踪表示计数器当前值的单个数字。

Redux 应用通常以 JS 对象作为状态树的根节点,其他值均存储在该对象内。

接着定义 reducer 函数。该函数接收两个参数:当前 state 和描述事件的 action 对象。Redux 应用启动时尚未初始化状态,因此将 initialState 作为 reducer 的默认值:

// Create a "reducer" function that determines what the new state
// should be when something happens in the app
function counterReducer(state = initialState, action) {
// Reducers usually look at the type of action that happened
// to decide how to update the state
switch (action.type) {
case 'counter/incremented':
return { ...state, value: state.value + 1 }
case 'counter/decremented':
return { ...state, value: state.value - 1 }
default:
// If the reducer doesn't care about this action type,
// return the existing state unchanged
return state
}
}

Action 对象总包含 type 字段——由你提供的字符串,作为 action 的唯一标识符。type 应具有可读性,使代码查看者能理解其含义。本例中,我们用 'counter' 作为 action 类型前缀,后缀描述'发生了什么'。此处 'counter' 被 'incremented'(增加),因此 action 类型写作 'counter/incremented'

根据 action 类型,我们需要返回全新对象作为新 state,或在无需更改时返回原 state 对象。注意:我们通过复制现有状态并更新副本来 不可变地(immutably) 更新状态,而非直接修改原对象。

Store

现在有了 reducer 函数,可通过 Redux 库的 createStore API 创建 store 实例:

// Create a new Redux store with the `createStore` function,
// and use the `counterReducer` for the update logic
const store = Redux.createStore(counterReducer)

将 reducer 函数传给 createStore,该函数会使用 reducer 生成初始状态并计算所有后续更新。

用户界面

任何应用中,用户界面都会在屏幕上展示当前状态。当用户执行操作时,应用会更新数据并用新值重绘 UI。

// Our "user interface" is some text in a single HTML element
const valueEl = document.getElementById('value')

// Whenever the store state changes, update the UI by
// reading the latest store state and showing new data
function render() {
const state = store.getState()
valueEl.innerHTML = state.value.toString()
}

// Update the UI with the initial data
render()
// And subscribe to redraw whenever the data changes in the future
store.subscribe(render)

本简单示例中,我们仅用基础 HTML 元素构建 UI,单个 <div> 显示当前值。

因此我们编写函数:通过 store.getState() 方法从 Redux store 获取最新状态,然后用该值更新 UI 显示。

Redux store 允许我们调用 store.subscribe() 并传入订阅者回调函数,该函数会在每次 store 更新时被调用。因此我们可以将 render 函数作为订阅者传入,这样每次 store 更新时,我们就能用最新值更新 UI。

Redux 本身是一个独立库,可在任何环境中使用。这也意味着它可以与任何 UI 层配合使用。

派发 Action

最后,我们需要通过创建描述发生事件的 action 对象来响应用户输入,并将其派发到 store。当我们调用 store.dispatch(action) 时,store 会运行 reducer 计算更新后的状态,并执行订阅者来更新 UI。

// Handle user inputs by "dispatching" action objects,
// which should describe "what happened" in the app
document.getElementById('increment').addEventListener('click', function () {
store.dispatch({ type: 'counter/incremented' })
})

document.getElementById('decrement').addEventListener('click', function () {
store.dispatch({ type: 'counter/decremented' })
})

document
.getElementById('incrementIfOdd')
.addEventListener('click', function () {
// We can write logic to decide what to do based on the state
if (store.getState().value % 2 !== 0) {
store.dispatch({ type: 'counter/incremented' })
}
})

document
.getElementById('incrementAsync')
.addEventListener('click', function () {
// We can also write async logic that interacts with the store
setTimeout(function () {
store.dispatch({ type: 'counter/incremented' })
}, 1000)
})

这里我们将派发使 reducer 在当前计数器值上加 1 或减 1 的 action。

我们也可以编写仅在特定条件为真时才派发 action 的代码,或编写在延迟后派发 action 的异步代码。

数据流

我们可以通过此图概括 Redux 应用中的数据流。它展示了:

  • 响应诸如点击之类的用户交互而派发 action

  • store 运行 reducer 函数以计算新状态

  • UI 读取新状态以显示新值

(如果这些部分还不完全清晰,别担心!在学习本教程剩余内容时,请将此图记在脑中,您会看到各部分如何协同工作。)

Redux 数据流程图

学习要点

计数器示例虽小,但它展示了真实 Redux 应用的所有工作部件。后续章节中我们将讨论的所有内容都是对这些基础部件的扩展。

有鉴于此,让我们回顾目前所学:

总结
  • Redux 是管理全局应用状态的库
    • 通常配合 React-Redux 实现 Redux 与 React 的集成
    • Redux Toolkit 是编写 Redux 逻辑的标准方式
  • Redux 的更新模式分离“事件描述”与“状态变更”
    • Action 是包含 type 字段的普通对象,描述应用中“发生了什么”
    • Reducer 是根据先前状态和 action 计算新状态的函数
    • 当 action 被 分发 时,Redux store 会运行根 reducer
  • Redux 采用“单向数据流”架构
    • 状态描述应用在特定时刻的状况,UI 基于该状态渲染
    • 事件触发时的处理流程:
      • UI 分发 action
      • store 运行 reducers 并根据事件更新状态
      • store 通知 UI 状态变更
    • UI 根据新状态重新渲染

下一步是什么?

既然您已了解 Redux 应用的基本部件,请继续学习第二部分:Redux 概念与数据流,我们将更详细地探讨数据如何在 Redux 应用中流动。