创建Reducer
对于Reducer的创建,同样需要与传统Redux中的Reducer创建方法进行对比。传统定义Reducer都是通过构建一个复杂的大型switch
表达式来完成的。
例如延续上一节示例中的Action对应的Reducer,就是以下示例中的样子。
const initialState = { value: 0 };
function counterReducer(state = initialState, action) {
switch (action.type) {
case 'counter/increase':
return { value: state.value + action.payload ?? 1 };
case 'counter/decrease':
return { value: state.value - action.payload ?? 1 };
default:
return state;
}
}
使用这种传统Reducer的创建方法最大的缺点就是在Reducer要处理Action类型繁多的Action时,switch
表达式的结构将变得非常庞大,并且难于管理。所以就更不用说每种Action类型再携带不同形式的载荷的情况了。
Redux Tookit针对Reducer定义时的这种特点,使用构造者模式对其进行了优化。虽然不能明显的减少Reducer所使用的代码量,但是可以让Reducer的定义变得更加清晰。
以下是采用Redux Toolkit提供的createReducer
函数完成上面示例中的Reducer创建的示例。
import { createAction, createReducer } from '@reduxjs/toolkit';
interface CounterState {
value: number;
}
const counterIncreaseBy1 = createAction('counter/increase');
const counterDecreaseBy1 = createAction('counter/decrease');
const counterIncreaseByAmount = createAction<number>('counter/increase');
const counterDecreaseByAmount = createAction<number>('counter/decrease');
// createReducer所接受的第一个参数是State的初始状态,第二个参数是处理传入的不同Action的函数。
// addCase方法主要接受使用createAction创建的Action创建函数作为其匹配条件。
// 除了addCase之外,createReducer还支持addMatcher方法,可以用于使用自定义函数进行匹配。
// addDefaultCase方法通常是用作最后的匹配处理,其不需要任何匹配条件,在之前的所有条件都不匹配时匹配,相当于switch表达式中的default。
const counterReducer = createReducer<CounterState>({ value: 0 }, builder => {
builder
.addCase(counterIncreaseBy1, (state, action) => {
state.value += 1;
})
.addCase(counterDecreaseBy1, (state, action) => {
state.value -= 1;
})
.addCase(counterIncreaseByAmount, (state, action) => {
state.value += action.payload;
})
.addCase(counterDecreaseByAmount, (state, action) => {
state.value -= action.payload;
})
.addDefaultCase((state, action) => state));
});
在使用createReducer
函数的时候需要注意addCase
、addMatcher
、addDefaultCase
之间的排列顺序。由于addMatcher
能够处理包括action.type
在内的附加了其他内容的Action载荷,所以需要放置在仅使用action.type
进行判断的addCase
之后,但是要放置在不需要任何判断条件的addDefaultCase
之前。
另外需要说明的一点是,因为createReducer
内部使用了Immer库对数据进行不可变处理,所以在匹配条件的回调函数中可以对State直接进行操作,createReducer
内部会将其转换为使用Immer库的操作。