2017-12-18 170 views
1

这里就是我试图做的一个例子:为什么我的Redux reducer重构失败?

const setView = state => payload => ({ ...state, view: payload }); 

const reducers = { 
    SET_VIEW: setView 
}; 

export default (state = initialState, action) => reducers[action.type](state)(action.payload); 

不幸的是,我得到以下错误:

Uncaught TypeError: reducers[action.type] is not a function

我究竟在做什么错? reducers是一个带有函数的对象文字。

+0

看起来它可以基于显示的内容工作。在发生错误的地方记录'redurs'的值是多少? – bazzells

+0

@bazzells Nope,Redux在商店创建时分派一个虚拟动作,OP不处理错误。查看我的答案了解更多详情。 – Li357

回答

2

这实际上是一个相当晦涩的问题。究其原因是因为,每the Redux documentation on createStore

When a store is created, Redux dispatches a dummy action to your reducer to populate the store with the initial state. You are not meant to handle the dummy action directly. Just remember that your reducer should return some kind of initial state if the state given to it as the first argument is undefined, and you're all set.

而且通过文档提到的只是让这个假动作恰好be this line the source

dispatch({ type: ActionTypes.INIT }) 

这里,ActionTypes.INIT基本上是跟着一个随机字符串,字符串@@redux/INIT数字和句点。

因此,当你与createStore创建存储,虚拟动作被分派到你的减速,和动作类型在reducers对象不存在,所以你得到的错误,undefined是不是一个函数。这就是为什么你总是有你的减速机默认情况下。例如,与switch语句,你总是返回状态的默认情况下:

switch(action.type) { 
    … 
    default: 
    return state; 
} 

默认情况下允许的动作捕捉如终极版本身派出诱敌动作。同样的原则也适用于你的代码:

export default (state = initialState, action) => reducers[action.type] ? reducers[action.type](state)(action.payload) : state; 

这种检查是否减速的reducers对象实际存在。如果是这样,它会调用减速器。如果不是,就像在默认情况下一样,只是返回状态。

+0

哦,哇,TIL。感谢您的解释!所以,必须进行三元检查似乎很愚蠢,我想我会坚持开关语句。有没有办法通过在'combineReducers'中做这个检查来避免这个三元组? – scarywolfman

+0

或者我应该在这里处理默认情况?我想通过使用对象字面量我会避免有一个默认情况下._。 – scarywolfman

+0

@scarywolfman我不这么认为。即使Redux的文档建议大致相同的代码[减少reducer样板](https://redux.js.org/docs/recipes/ReducingBoilerplate.html#generating-reducers),尽管更具可读性。我认为它很好。 – Li357

1

@ Li357是正确的,为什么你会得到这样的错误。我想提出一个替代解决问题的办法:

const setView = state => payload => ({ ...state, view: payload }); 

const reducers = { 
    SET_VIEW: setView 
}; 

const noop = state =>() => state; 

export default (state = initialState, action) => (reducers[action.type] || noop)(state)(action.payload); 

这里的窍门是(reducers[action.type] || noop)部分,将使用一个noop处理程序,如果没有为动作类型的已知处理程序。它所做的就是返回当前状态。

+0

生病了!谢谢 – scarywolfman