Redux是一种更好的写减速器的方法吗?

时间:2018-03-01 19:06:08

标签: reactjs typescript redux react-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失败)
  • 总是调用所有reducers(调用函数什么也不做就是错误的)

......最后减速器成为项目的弱点/缰绳

问:是否有更好的方法/选项来编写减速器:

  • 仅针对特定操作(基于操作对象的类型)调用
  • 取消了switch语句

更像这样的事情:

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

或者是否有一个库已经这样做了?

4 个答案:

答案 0 :(得分:4)

请阅读"Reducing Boilerplate" docs page,了解如何编写自己的reducer实用程序的示例,例如将操作类型查找表添加到每种类型的特定reducer函数的函数。具体做法是:

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

"Structuring Reducers" docs section还提供了有关组织减速器逻辑的说明和想法。

有关详细信息,请参阅:

请记住:Redux调用你的 root reducer函数,这是编写的代码。减速器的工作原理是你的选择。如果您不喜欢切换语句,请不要编写它们。如果您发现代码重复,请编写工厂函数。

答案 1 :(得分:0)

您可以创建此类模块:



// 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};
        },
    }
);




答案 2 :(得分:0)

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

  

reducer太通用了(如果没有别的东西可以打破单一责任原则,你可以逐字写出臃肿的减速器来处理各种不同的动作并轻易造成混乱)

我认为减速器不太通用,他们的工作就是回归状态 您可以为整个状态设置一个reducer或将其拆分为较小的位以处理状态的某些部分。有时候,国家的一部分“关心”国家另一部分的变化,因此能够处理不同的行动是有利的。

  

switch语句强加维护方面的影响,例如对一个案例的更改可能会破坏其他案例(例如已经有效的代码)

您可以使用if语句。 the docs tackles this as well
虽然我不确定我理解 - “一个案件的改变可以打破其他案件”
您的意思是当字符串更改为"ADD_TODO"更改为"add_todo"时? 如果是这种情况,那么您可以在任何需要的地方使用变量并import

  

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

我可能同意这一点,但这是一个非常小的代价,以支付收听所发送的每一个行动的好处(如上所述)。无论如何,有办法编写“工厂”功能来处理减速器,我只是认为它是一个开销。

  

总是调用所有reducers(调用函数什么也不做就是错误的)

同样,我认为这是一个巨大的收获,而不是一种损失。

答案 3 :(得分:0)

检出有关通用reducer和动作创建器的github项目。它将解决您对样板代码的担忧。

Redux-Reducer-Generator