React/Redux reducer returned undefined during initialization

时间:2017-04-10 02:31:13

标签: javascript reactjs redux react-redux

I'm working on my first React/Redux project. Everything was going fine, and then I tried to create a new reducer. I thought it was a pretty simple one, but when I load the page I get an error "Reducer X returned undefined during initialization." The trace says this is happening in combineReducers(). I found a couple of similar questions, but they didn't solve the issue.

On this question: Why do I get “Reducer [...] returned undefined during initialization” despite providing initialState to createStore()?

The issue was that they were using initialState in createStore(), which I'm not doing.

On this question: Why does my Redux reducer think my state is undefined?

The problem was a missing default return value in the reducer, which I have.

My reducer code is below. I have a console.log() at the beginning and it is not being called at all.

reducers/reducer_which_sorter.js

import { SORT_CAMPERS } from '../actions/index';

export default function(state = null, action) {
    console.log("action is", action);
    switch(action.which) {
        case 'recent':
        case 'alltime':
            return action.which;
            break;
        default:
            return state;
    }

    return state;
}

reducers/index.js

import { combineReducers } from 'redux';
import Campers from './reducer_camper_list';
import ActiveSorter from './reducer_which_sorter';

const rootReducer = combineReducers({
  campers: Campers,
  activeSorter: ActiveSorter
});

export default rootReducer;

Everything compiles fine. No errors from webpack. I've double, triple and quadruple checked my file paths. I don't see any typos. Can anyone see something I am missing here?

4 个答案:

答案 0 :(得分:3)

  

我在开头有一个console.log(),根本没有被调用。

很奇怪,因为必须使用@@INIT操作至少调用一次reducer函数。

尝试测试您的rootReducer是否完全被调用。将其更改为:

const rootReducer = (state = {}, action) => {
  console.log('Test if rootReducer is ever called')

  return {
    campers: Campers(state.campers, action),
    activeSorter: ActiveSorter(state.activeSorter, action)
  }
}

如果没有被调用,那么问题就在某个地方,而不是在减速器本身。

答案 1 :(得分:3)

Redux要求是对操作使用type属性,而不是which,就像您在示例中所做的那样。由于未调用console.log检查,问题可能在您的其他reducer中(未在您的问题中显示)。

重要的是combineReducers使用特殊的INIT操作类型调用reducer函数:

const initialState = reducer(undefined, { type: ActionTypes.INIT })

来源:https://github.com/reactjs/redux/blob/master/src/combineReducers.js

你的函数,因为它打开'action.which'而不是'action.type',除了undefined之外都无法返回任何内容。

答案 2 :(得分:0)

当您的return语句未返回有效对象时,将发生此错误。当您看到此错误时,请始终检查您的reducer返回的内容。

另一个有趣的场景,我正在创建一个基本的redux应用程序,并引发了同样的错误,在我的情况下,我只是返回一个对象数组并得到了同样的错误,一切都很好我把头撞到了墙上终于发现这是由于 非常非常基本的 javascript错误。

return语句检查同一行中的值,并且不考虑下一行。

export default function(){
  return     // '[' should be here not in the next line ** basic mistake****
  [
      {
        id: 1,
        name: "sachin",
        centuries: "100",
        country: "India"
      },
      {
        id: 2,
        name: "ganguly",
        centuries: "42",
        country: "India"
      },
      {
        id:3,
        name: "dravid",
        centuries: "40",
        country: "India"
      }
    ]

}

由于javascript返回未定义,combineReducers函数未收到预期的对象而是未定义。

确保您拥有正确的return语句

答案 3 :(得分:0)

在组装化简器时,您将在switch语句中从动作创建者action.type属性传入type。动作创建者中没有which属性,它将传递给化简器。

记住,动作创建者总是将纯JavaScript动作对象传递给化简器。即使中间件(例如Redux-Thunk)接收到了该函数的功能,该中间件最终仍会将动作创建者功能修改为一个动作对象,以发送给您的所有reducer。

此外,您的案例还必须是操作类型本身的值。因此,可以说您的动作创建者是异步的,它是从某个端点获取数据的,看起来像这样:

export const allTime = () => async dispatch => {
  const response = await someEndPoint.get("/all");
  dispatch({ type: 'ALL_TIME', payload: response })
};

除了要在动作type属性中传递您的开关外,大小写必须是该type属性的值,在本示例中为'ALL_TIME',并且您想返回该动作创建者的有效载荷,如果您告诉我payload属性正在返回which,则上面的内容将如下所示:

export const allTime = () => async dispatch => {
  const which = await someEndPoint.get("/all");
  dispatch({ type: 'ALL_TIME', payload: which })
};

否则,您很可能会返回payload: response

所以代替:

export default function(state = null, action) {
    console.log("action is", action);
    switch(action.which) {
        case 'recent':
        case 'alltime':
            return action.which;
            break;
        default:
            return state;
    }

    return state;
}

尝试:

export default function(state = null, action) {
    console.log("action is", action);
    switch(action.type) {
        case 'ALL_TIME':
            return action.response;
        default:
            return state;
    }
};

看看上面的重构对您有什么帮助,如果不能解决错误,我相信它将使您更接近目标。如果您需要重新开始,请紧记JavaScript规则,那么函数必须始终return带有一些值,因此您可能需要返回到:

export default () => {
   return 123;
};

如果您实现了您的错误消息肯定会消失,那么您可以利用这段时间在SO上考虑问题的答案,并从中反思解决方案。你甚至可以实现:

export default () => {
   return ‘howdy’;
};

您可以返回一个空数组:

export default () => {
   return [];
};

您可以返回一个对象:

export default () => {
   return {};
};

您甚至可以像这样返回null值:

export default () => {
   return null;
};

,您的错误消息将消失。现在的问题是您的逻辑,等同于执行此操作:

export default () => {
  return undefined;
}

在减速器领域这是不可接受的。

您会看到错误,指出初始化期间返回了未定义的错误。因此,当Redux首次启动时,它将一次运行每个reducer。

因此,这意味着您的reducer第一次运行时会返回undefined的值,无论是在初始化时还是在调度操作的将来某个时刻,reduce都永远不会返回undefined。

因此,对于reducer,您必须始终返回除undefined之外的任何值。