Basic Reducer Structure: Overview of how reducer functions work with Redux state">Basic Reducer Structure: Overview of how reducer functions work with Redux state">
跳至主要内容

基本 Reducer 结构和状态形状

基本 Reducer 结构

首先,重要的是要理解您的整个应用程序实际上只有一个单一的 reducer 函数:您传递给 createStore 作为第一个参数的函数。这个单一的 reducer 函数最终需要做几件事

  • reducer 第一次被调用时,state 值将为 undefined。reducer 需要处理这种情况,在处理传入的操作之前提供一个默认状态值。
  • 它需要查看先前状态和分派的 action,并确定需要完成哪些工作
  • 假设需要进行实际更改,则需要使用更新后的数据创建新的对象和数组,并返回这些对象和数组。
  • 如果不需要进行任何更改,则应按原样返回现有状态。

编写 reducer 逻辑的最简单方法是将所有内容都放在一个函数声明中,如下所示

function counter(state, action) {
if (typeof state === 'undefined') {
state = 0 // If state is undefined, initialize it with a default value
}

if (action.type === 'INCREMENT') {
return state + 1
} else if (action.type === 'DECREMENT') {
return state - 1
} else {
return state // In case an action is passed in we don't understand
}
}

请注意,这个简单的函数满足了所有基本要求。如果不存在,它会返回一个默认值,初始化存储;它根据操作的类型确定需要进行哪种更新,并返回新值;如果不需要进行任何工作,它会返回先前状态。

可以对这个 reducer 进行一些简单的调整。首先,重复的 if/else 语句很快就会变得令人厌烦,因此使用 switch 语句非常常见。其次,我们可以使用默认参数值来处理初始的“不存在数据”情况。进行这些更改后,reducer 将如下所示

function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}

这是典型的 Redux reducer 函数使用的基本结构。

基本状态形状

Redux 鼓励您从需要管理的数据的角度考虑您的应用程序。任何给定时间点的数据都是应用程序的“状态”,该状态的结构和组织通常被称为其“形状”。状态的形状在您如何构建 reducer 逻辑方面起着重要作用。

Redux 状态通常在状态树的顶部有一个纯 JavaScript 对象。(当然可以使用其他类型的数据,例如单个数字、数组或专门的数据结构,但大多数库都假设顶层值为纯对象。)在该顶层对象中组织数据的最常见方法是将数据进一步划分为子树,其中每个顶层键代表某个“域”或相关数据的“切片”。例如,基本 Todo 应用程序的状态可能如下所示

{
visibilityFilter: 'SHOW_ALL',
todos: [
{
text: 'Consider using Redux',
completed: true,
},
{
text: 'Keep all state in a single tree',
completed: false
}
]
}

在这个示例中,todosvisibilityFilter 都是状态中的顶层键,并且每个键都代表某个特定概念的数据“切片”。

大多数应用程序处理多种类型的数据,这些数据可以大致分为三类

  • 域数据:应用程序需要显示、使用或修改的数据(例如“从服务器检索到的所有 Todo”)
  • 应用程序状态:特定于应用程序行为的数据(例如“Todo #5 当前已选中”或“正在进行请求以获取 Todo”)
  • UI 状态:表示 UI 当前显示方式的数据(例如,“EditTodo 模态对话框当前处于打开状态”)。

由于 store 代表应用程序的核心,因此您应该根据您的领域数据和应用程序状态来定义您的状态形状,而不是您的 UI 组件树。例如,state.leftPane.todoList.todos 的形状是一个不好的主意,因为“todos”的概念是整个应用程序的核心,而不仅仅是 UI 的一部分。todos 切片应该位于状态树的顶部。

您的 UI 树和状态形状之间很少会存在一对一的对应关系。唯一的例外可能是您在 Redux store 中显式跟踪 UI 数据的各个方面,但即使那样,UI 数据的形状和领域数据的形状也可能不同。

典型应用程序的状态形状可能大致如下所示

{
domainData1 : {},
domainData2 : {},
appState1 : {},
appState2 : {},
ui : {
uiState1 : {},
uiState2 : {},
}
}