基本 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
}
]
}
在这个示例中,todos
和 visibilityFilter
都是状态中的顶层键,并且每个键都代表某个特定概念的数据“切片”。
大多数应用程序处理多种类型的数据,这些数据可以大致分为三类
- 域数据:应用程序需要显示、使用或修改的数据(例如“从服务器检索到的所有 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 : {},
}
}