【问题标题】:React/Redux reducer returned undefined during initializationReact/Redux reducer 在初始化期间返回 undefined
【发布时间】:2017-09-04 23:12:21
【问题描述】:

我正在开发我的第一个 React/Redux 项目。一切都很顺利,然后我尝试创建一个新的减速器。我认为这是一个非常简单的问题,但是当我加载页面时,我收到一个错误“Reducer X 在初始化期间返回未定义”。跟踪表明这发生在 combineReducers() 中。我发现了几个类似的问题,但没有解决问题。

关于这个问题:Why do I get “Reducer [...] returned undefined during initialization” despite providing initialState to createStore()?

问题是他们在 createStore() 中使用了 initialState,而我没有这样做。

关于这个问题:Why does my Redux reducer think my state is undefined?

问题是减速器中缺少默认返回值,我有。

我的减速器代码如下。我在开始时有一个 console.log() 并且根本没有被调用。

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;

一切都编译得很好。 webpack 没有错误。我已经两次、三次和四次检查了我的文件路径。我没有看到任何错别字。谁能看到我在这里缺少的东西?

【问题讨论】:

  • 在抛出错误的行上下断点并刷新页面。然后,当它在调试器中中断时 - 您将了解所发生情况的完整详细信息。

标签: javascript reactjs redux react-redux


【解决方案1】:

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

这很重要的原因是 combineReducers 正在使用特殊的 INIT 操作类型调用您的减速器函数:

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

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

您的函数,因为它打开了“action.which”而不是“action.type”,所以除了未定义之外,没有返回任何东西。

【讨论】:

  • 我改变了我的逻辑,所以这段代码在我的另一个减速器中,因为它实际上只有一行。现在一切正常。我认为你是对的,因为它是开关。
【解决方案2】:

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

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

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

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

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

如果它没有被调用,那么问题出在更高的地方,而不是减速器本身。

【讨论】:

    【解决方案3】:

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

    一个更有趣的场景,我正在创建一个基本的 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 语句

    【讨论】:

      【解决方案4】:

      当组合一个 reducer 时,在你的 switch 语句中,你将传递一个来自 action creators type 属性的 action.type。动作创建者中没有which 属性,它将传递给reducer。

      请记住,动作创建者总是将纯 JavaScript 动作对象传递给减速器。即使它是一个被 Redux-Thunk 等中间件接收的函数,该中间件最终也会将 action creators 函数修改为一个 action 对象,以发送到所有 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 的值,你的 reducer 永远不会返回 undefined,无论是在初始化时还是在未来某个时间分派操作时。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-02-21
        • 1970-01-01
        • 2018-06-05
        • 2019-05-28
        • 1970-01-01
        • 2021-07-02
        • 2019-11-22
        相关资源
        最近更新 更多