Redux 编写化简器的更好方法?



我认为 Redux 有很多价值,但对我来说,主要问题在于今天如何编写化简器:

const addToDoReducer = (state, action) => {
switch (action.type) {
case ADD_TODO:
return Object.assign({}, state, {
todos: todos(state.todos, action)
})
case TOGGLE_TODO:
return Object.assign({}, state, {
todos: todos(state.todos, action)
})
default:
return state
}
}
  • 化简器太通用了(你可以从字面上写出处理各种不同动作的臃肿化简器,很容易造成混乱)如果没有别的,这违反了单一责任原则
  • switch 语句施加维护副作用,例如对一个案例的更改可能会破坏其他情况(例如,已经工作的代码)
  • 总是重复"默认:返回状态"(DRY 失败)
  • 所有化简器总是被调用(调用函数不做任何事情是错误的)

。这在最后成为项目的弱点/缰绳点

问:有没有更好的方法/选项来编写化简器:

  • 仅为特定操作调用(基于操作对象的类型)
  • 消除开关语句

更像这样的东西:

const addToDoReducer = (state:toDoState, action:addAction) =>
{
return { ...state, toDos: [...state.toDos, action.toDoObject] };
}

还是已经有图书馆这样做了?

请阅读"减少样板"文档页面,了解如何编写自己的化简器实用程序的示例,例如将操作类型的查找表转换为每种类型的特定化简器函数的函数。 具体说来:

function createReducer(initialState, handlers) {
return function reducer(state = initialState, action) {
if (handlers.hasOwnProperty(action.type)) {
return handlers[action.type](state, action)
} else {
return state
}
}
}

"构建化简器"文档部分还提供了有关如何组织化简器逻辑的说明和想法。

欲了解更多信息,请参阅:

  • 关于"调用所有化简器"和性能的 Redux FAQ 条目
  • 有关使用 switch 语句的 Redux 常见问题条目
  • 我的博客文章 Redux 的道,第 2 部分 - 实践与哲学,其中专门讨论了这样一个事实,即是否使用 switch 语句以及如何编写化简器逻辑完全取决于您
  • Redux插件化简器实用程序库的目录列表

请记住:Redux 调用您的根化简器函数,这是编写的代码。 减速器如何工作是您的选择。 如果你不喜欢 switch 语句,就不要写它们。 如果发现代码重复,请编写工厂函数。

您可以创建这样的模块:

// createReducer.js
export default (initiateState, reducerMap) => {
return function(state, action) {
const currentState = state !== undefined ? state : initiateState;
const handler = reducerMap[action.type];
return handler ? handler(currentState, action) : currentState;
};
};

然后,在第一个参数中设置初始状态,并将操作列表存储为对象。例如:

import createReducer from './createReducer';
const STORE_TEST_MODULE = 'STORE_TEST_MODULE';
export default createReducer(
// Initial state
{
test: null,
},   
{
// Custom action #1
[STORE_TEST_MODULE]: (state, action) => {
return {...state, ...action.payload};
},
// Custom action #2
'CLEAR_TEST': (state, action) => {
return {test: null};
},
}
);

不确定这是否有资格作为答案,但太多字符无法评论:)

化简器太通用了(你可以从字面上写出处理各种不同动作的臃肿化简器,很容易造成混乱)如果没有别的,这违反了单一责任原则

我不认为化简器太通用,他们的工作是回报状态。
您可以为整个状态设置一个reducer,也可以将其拆分为较小的位以处理状态的某些部分。但有时,国家的一部分"关心"国家另一部分的变化,因此能够处理不同的行动是一个优势。

switch 语句施加维护副作用,例如对一个案例的更改可能会破坏其他情况(例如,已经工作的代码)

您可以使用if语句。 文档也解决了这个问题。
虽然我不确定我是否理解 -"对一个案例的更改可能会破坏其他案例">
你的意思是当字符串被更改时,就像"ADD_TODO"更改为"add_todo"
?如果是这种情况,那么您可以使用变量,并在您需要的任何地方import它们。

总是重复"默认:返回状态"(DRY 失败)

我可能同意这一点,但这是一个非常小的代价,可以支付监听每个调度动作的好处(如上所述)。无论如何,有一些方法可以编写"工厂"函数来处理化简器的问题,我只是认为这是一个开销。

所有化简器总是被调用(调用函数不做任何事情是错误的)

同样,我认为这是巨大的收益,而不是损失。

查看我在通用化简器和操作创建器上的 github 项目。它将解决您对样板代码的担忧。

冗余-减速器-生成器

最新更新