跳至主内容
非官方测试版翻译

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

Reducer 基础结构与状态形态

Reducer 基础结构

首先需要明确的是,整个应用实际上只有一个 reducer 函数:即作为第一个参数传递给 createStore 的函数。这个核心 reducer 函数需要完成以下几项工作:

  • reducer 首次被调用时,state 值为 undefined。需要提供默认状态值后再处理 action

  • 需要检查前次状态和派发的 action,确定需要执行的操作类型

  • 当需要实际变更时,创建包含更新数据的新对象/数组并返回

  • 如无需变更,则直接返回原状态

最简单的实现方式是使用单一函数声明,如下所示:

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
}
}

该基础函数满足所有核心需求:初始化存储(无值时返回默认值);根据 action 类型确定更新逻辑并返回新值;无操作时返回原状态

可对此 reducer 进行两处优化:使用 switch 替代重复的 if/else;通过默认参数处理初始空状态。优化后示例如下:

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 对象作为顶层结构(虽支持其他类型如数字/数组,但多数库默认顶层为对象)。常见组织方式是将数据划分为子树,每个顶层键代表特定"领域"或"切片"。例如待办应用的状态可能如下:

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

此例中 todosvisibilityFilter 均为顶层键,各自代表特定概念的"数据切片"

多数应用处理三类数据:

  • 领域数据:应用需展示/使用/修改的数据(如"从服务器获取的所有待办项")

  • 应用状态:特定于应用行为的数据(如"待办项#5 当前被选中"或"正在获取待办项的请求")

  • UI 状态:描述界面显示的数据(如"编辑待办项的模态框当前处于打开状态")

因 store 是应用核心,状态形态应基于领域数据和应用状态定义,而非 UI 组件结构。例如 state.leftPane.todoList.todos 的形态不可取,因"待办项"是全局核心概念,todos 应置于状态树顶层而非 UI 局部

你的 UI 树和状态结构之间很少存在一对一的对应关系。唯一的例外是当你明确在 Redux store 中跟踪 UI 数据时,即便如此,UI 数据的结构通常也会与领域数据的结构不同。

一个典型应用的状态结构大致如下:

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