Why does my Redux reducer refactor fail?

时间:2017-12-18 05:39:11

标签: javascript ecmascript-6 redux

Here is an example of what I'm attempting to do:

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

const reducers = {
  SET_VIEW: setView
};

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

Unfortunately, I get the following error:

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

What exactly am I doing wrong? reducers is an object literal with functions.

2 个答案:

答案 0 :(得分:2)

This is quite an obscure issue actually. The reason is because, per 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.

And this dummy action mentioned by the documentation just so happens to be this line the source:

dispatch({ type: ActionTypes.INIT })

Here, ActionTypes.INIT is essentially the string @@redux/INIT followed by a random string of numbers and periods.

Thus, when you create the store with createStore, a dummy action is dispatched to your reducer, and that action type does not exist in your reducers object, thus you get the error that undefined isn't a function. That's why you always have a default case in your reducer. For example, with a switch statement, you always return state as a default case:

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

The default case allows for the catching of actions such as the dummy action dispatched by Redux itself. The same principle applies to your code:

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

This checks to see if the reducer actually exists in the reducers object. If it does, it calls the reducer. If not, just like in the default case, the state is just returned.

答案 1 :(得分: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处理程序。它只是返回当前状态。

相关问题