本页面由 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
}
]
}
此例中 todos 和 visibilityFilter 均为顶层键,各自代表特定概念的"数据切片"
多数应用处理三类数据:
-
领域数据:应用需展示/使用/修改的数据(如"从服务器获取的所有待办项")
-
应用状态:特定于应用行为的数据(如"待办项#5 当前被选中"或"正在获取待办项的请求")
-
UI 状态:描述界面显示的数据(如"编辑待办项的模态框当前处于打开状态")
因 store 是应用核心,状态形态应基于领域数据和应用状态定义,而非 UI 组件结构。例如 state.leftPane.todoList.todos 的形态不可取,因"待办项"是全局核心概念,todos 应置于状态树顶层而非 UI 局部
你的 UI 树和状态结构之间很少存在一对一的对应关系。唯一的例外是当你明确在 Redux store 中跟踪 UI 数据时,即便如此,UI 数据的结构通常也会与领域数据的结构不同。
一个典型应用的状态结构大致如下:
{
domainData1 : {},
domainData2 : {},
appState1 : {},
appState2 : {},
ui : {
uiState1 : {},
uiState2 : {},
}
}