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?
答案 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之外的任何值。