React 实践:改造 Redux action generator,编写 Redux reducer generator (2)
背景
接上一篇博文,我们来探讨一下怎么通过配置来生成 reducer
,以及如何往自动生成的 reducer
中增加自定义的转换(action
触发 reducer
变化)
reducer 的组成
- 在上一篇博文中,我们通过 action 的配置,自动生成了一些 reducer,这一部分我们称为
来自 action 配置的 reducer
- 我们自定义的 reducer,需要定义名字以及它对应的通过 action 之后的转换(nextState)
- 由 action 配置自动生成的 reducer,我们往其中增加一些转换规则
完善 reducer_generator
我们可以把 reducer 的配置分为两部分:basics(自定义 reducer) 和 extras(往自动生成的 reducer 中添加规则)
basics 和 extras 的配置规则差不多,不同的是 basics 的每个元素多了一个 initialState 属性,如下例子所示
[
{
name: 'globalLoading',
initialState: {
show: false,
msg: '
},
mappers: [
{
action: 'showLoading',
nextState: (state, action) => ({
show: true,
msg: action.data || 'loading'
})
},
{
action: 'hideLoading',
nextState: (state, action) => ({
show: false,
msg: ''
})
}
]
}
]
和我们原来写 reducer 的方式很像,只不过变成了配置,简化了代码。
最终的 reducer 通过这个函数暴露出去
export default (prefix, actionConfigs, reducerConfigs) => {
const result = {};
forEach(action =>
addReducersFromAction(prefix, action, result, reducerConfigs.extras || [], actionLoadingList)
)(actionConfigs);
forEach(reducer =>
addReducersFromBasicConfigs(prefix, reducer, result)
)(reducerConfigs.basics || []);
return result;
};
自定义 reducer
其实也就是实现 addReducersFromBasicConfigs
函数,很简单,代码如下
const addReducersFromBasicConfigs = (prefix, reducer, result) => {
const {
name, initialState, mappers
} = reducer;
result[`${name}`] = (state = initialState, action) => {
for (let i = 0, length = mappers.length; i < length; i ++) {
const mapper = mappers[i];
if (action.type === getAction(prefix, `${mapper.action}`)) {
return mapper.nextState(state, action);
}
}
return state;
};
};
补充自动生成的 reducer 规则
我们在上一篇博文已经看到了,对于每一种类型的 action,都有对应的 reducer_generator 代码。
为了实现规则的补充,我们让自动生成的 reducer 在经过自动生成的规则的判断之后,返回一个函数。
比如 loading 的代码,我们修改如下
result[`${name}Loading`] = (state = false, action) => {
if (action.type === getAction(prefix, name, defines.ACTION_STATUS_LOAD)) {
return true;
}
if (action.type === getAction(prefix, name, defines.ACTION_STATUS_SUCCESS)) {
return false;
}
if (action.type === getAction(prefix, name, defines.ACTION_STATUS_FAIL)) {
return false;
}
return getExtraMapper(prefix, `${name}Loading`, state, action, extras);
};
其中,getExtraMapper 函数就是我们处理自定义规则的地方。该函数代码如下
const getExtraMapper = (prefix, name, state, action, extras) => {
for (let i = 0, length = extras.length; i < length; i ++) {
const extra = extras[i];
if (extra.name === name) {
for (let j = 0, mappersLength = extra.mappers.length; j < mappersLength; j ++) {
const mapper = extra.mappers[j];
if (action.type === getAction(prefix, mapper.action)) {
return mapper.nextState(state, action);
}
}
}
}
return state;
};
思路很简单,就是遍历 extras 的配置,从中寻找匹配的 name,然后将规则添加进去,是不是很简单?
总结
至此,我们就实现了通过配置生成所有的 action 和 reducer 的方法,让项目代码量骤减,开发效率也提高了不少。