Javascript 尽管为 createStore() 提供了 initialState,为什么我仍然得到“Reducer [...] 在初始化期间返回未定义”?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/36619093/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why do I get “Reducer [...] returned undefined during initialization” despite providing initialState to createStore()?
提问by Ice Wilder
I had set InitialState in my redux createStore method ,and I corresponding InitialState as second arguments
我在 redux createStore 方法中设置了 InitialState,并将 InitialState 作为第二个参数
I got a error in browser:
我在浏览器中遇到错误:
<code>Uncaught Error: Reducer "postsBySubreddit" returned undefined during initialization. If the state passed to the reducer is undefined, you must explicitly return the initial state. The initial state may not be undefined.</code>
code is here:
代码在这里:
import { createStore, applyMiddleware } from 'redux'
import thunkMiddleware from 'redux-thunk'
import createLogger from 'redux-logger'
import rootReducer from '../reducers/reducers'
import Immutable from 'immutable'
const loggerMiddleware = createLogger()
//const initialState=0
function configureStore() {
return createStore(
rootReducer,
{postsBySubreddit:{},selectedSubreddit:'reactjs'},
applyMiddleware(
thunkMiddleware,
loggerMiddleware
)
)
}
export default configureStore
and I invoked configeStore
method in Root.js
:
我调用了configeStore
方法Root.js
:
import React, { Component } from 'react'
import { Provider } from 'react-redux'
import configureStore from '../store/configureStore'
import AsyncApp from './AsyncApp'
import Immutable from 'immutable'
const store = configureStore()
console.log(store.getState())
export default class Root extends Component {
render() {
return (
<Provider store={store}>
<AsyncApp />
</Provider>
)
}
}
but I guess this initateState
has something wrong:
但我想这initateState
有问题:
import { combineReducers } from 'redux'
import {reducerCreator} from '../utils/creator'
import Immutable from'immutable'
import {SELECT_SUBREDDIT, INVALIDATE_SUBREDDIT ,REQUEST_POSTS, RECEIVE_POSTS} from '../actions/action'
let initialState=Immutable.fromJS({isFetching: false, didInvalidate: false,items:[]})
function selectedSubreddit(state, action) {
switch (action.type) {
case SELECT_SUBREDDIT:
return action.subreddit
default:
return state
}
}
function postsBySubreddit(state, action) {
switch (action.type) {
case INVALIDATE_SUBREDDIT:
case RECEIVE_POSTS:
case REQUEST_POSTS:
return Object.assign({}, state, {
[action.subreddit]: posts(state[action.subreddit], action)
})
default:
return state
}
}
function posts(state=initialState,action) {
switch (action.type) {
case INVALIDATE_SUBREDDIT:
return state.merge({
didInvalidate: true
})
case REQUEST_POSTS:
return state.merge({
isFetching: true,
didInvalidate: false
})
case RECEIVE_POSTS:
return state.merge({
isFetching: false,
didInvalidate: false,
items: action.posts,
lastUpdated: action.receivedAt
})
default:
return state
}
}
const rootReducer = combineReducers({
postsBySubreddit,
selectedSubreddit
})
export default rootReducer
but if I set initialState
in my every sub reducer it can did word normally. Something wrong?
但是如果我initialState
在我的每个子减速器中设置它可以正常做词。有问题?
回答by Dan Abramov
The initialState
argument in createStore()
is often tripping people. It was never meant as a way to “initialize” your application state manually. The only useful applications for it are:
中的initialState
论点createStore()
常常使人绊倒。它从来都不是一种手动“初始化”应用程序状态的方法。它唯一有用的应用程序是:
- Booting up server rendered app from JSON state payload.
- “Resuming” the app from a state saved into local storage.
- 从 JSON 状态负载启动服务器呈现的应用程序。
- 从保存到本地存储的状态“恢复”应用程序。
It is implied that you never write initialState
manually and in most apps you don't even use it. Instead, reducers must always specify their own initial state, and initialState
is just a way to prefill that state when you have an existing serialized version of it.
这暗示您从不initialState
手动编写,并且在大多数应用程序中您甚至不使用它。相反,reducer 必须始终指定它们自己的初始状态,并且initialState
这只是当您拥有它的现有序列化版本时预填充该状态的一种方式。
So this answeris correct: you needto define the initial state in your reducer. Supplying it to createStore()
is not enough, and is not meant to be a way to define the initial state in code.
所以这个答案是正确的:你需要在你的减速器中定义初始状态。提供它createStore()
是不够的,也不意味着是在代码中定义初始状态的一种方式。
回答by Isaac Pak
I had the same error but I didn't include a default case
我有同样的错误,但我没有包含默认情况
function generate(state={} ,action) {
switch (action.type) {
case randomNumber:
return {
...state,
random: action.payload
}
default: // need this for default case
return state
}
}
回答by Florian Cargoet
When your reducers are called for the first time, state is undefined. You must then return the initial state (that's what the error message is telling you). The usual way of defining the initial state value is to set a default value for the state parameter:
当您的减速器第一次被调用时,状态是未定义的。然后您必须返回初始状态(这是错误消息告诉您的)。定义初始状态值的常用方法是为 state 参数设置一个默认值:
function postsBySubreddit(state = {}, action) {}
You have an initial state in the posts
function but it is not called during initialization.
您在posts
函数中有一个初始状态,但在初始化期间不会调用它。
回答by TechnoTim
Also, make sure that you are returning the default statelast in your reducer. Sometimes you can forget to make sure this is the default for your switch statement (when refactoring and moving around code).
另外,请确保您在减速器中最后返回默认状态。有时您可能忘记确保这是 switch 语句的默认值(在重构和移动代码时)。
...
default:
return state
回答by duhaime
I just hit this same snag because I accidentally redefined state
inside my reducer:
我只是遇到了同样的问题,因为我不小心state
在减速器中重新定义了:
const initialState = {
previous: true,
later: true
}
const useTypeReducer = (state = initialState, action) => {
switch (action.type) {
case 'TOGGLE_USE_TYPES':
let state = Object.assign({}, state); // DON'T REDEFINE STATE LIKE THIS!
state[action.use] = !state[action.use];
return state;
default:
return state;
}
}
export default useTypeReducer;
To fix the problem I needed to refrain from redefining state:
为了解决这个问题,我需要避免重新定义状态:
const initialState = {
previous: true,
later: true
}
const useTypeReducer = (state = initialState, action) => {
switch (action.type) {
case 'TOGGLE_USE_TYPES':
let _state = Object.assign({}, state); // BETTER
_state[action.use] = !state[action.use];
return _state;
default:
return state;
}
}
export default useTypeReducer;
回答by totymedli
tl;dr
tl;博士
Make sure that:
确保:
- You actually pass data to your reducer via the action/action creator!
- The reducer doesn't return
undefined
.
- 你实际上是通过动作/动作创建者将数据传递给你的减速器!
- 减速器不返回
undefined
。
Example
例子
const reducer = (state = initialState, action) => {
switch (action.type) {
case 'SET_DATA':
debugger // Place a breakpoint for investigation
const result = update(state, {$set: action.data});
// `result` is `undefined` if `action.data` is too
return result;
default:
return state;
}
}
In this case, if you accidentally pass undefined
to action.data
via your action creator then react-addons-updatewill return the undefined
that came from that variable. Since this overwrites the whole reducer state it will return that undefined
that will trigger the error.
在这种情况下,如果你不小心通过你的动作创建者传递undefined
到action.data
,那么react-addons-update将返回undefined
来自该变量的 。由于这会覆盖整个减速器状态,因此它将返回undefined
将触发错误的状态。
Debugging
调试
You can debug this by examining these places:
您可以通过检查这些地方来调试它:
- Where the reducer creates the new state. Place a breakpoint into that part to make sure you don't receive or return
undefined
there. - Where the data is passed to the action creator.
- 减速器创建新状态的地方。在该部分放置一个断点以确保您不会收到或返回
undefined
那里。 - 数据传递给动作创建者的地方。