尽管为 createStore() 提供了 initialState,但为什么我会得到“Reducer [...] 在初始化期间返回未定义”?
Why do I get “Reducer [...] returned undefined during initialization” despite providing initialState to createStore()?
我已经在我的 redux createStore 方法中设置了 InitialState,并且我相应的 InitialState 作为第二个参数
我在浏览器中遇到错误:
<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>
代码在这里:
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
并且我在 Root.js
中调用了 configeStore
方法:
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>
)
}
}
但我猜这个 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
但是如果我在我的每个子减速器中设置 initialState
它可以正常做词。有问题?
当你的减速器第一次被调用时,状态是未定义的。然后您必须 return 初始状态(这就是错误消息告诉您的内容)。
定义初始状态值的通常方法是为状态参数设置一个默认值:
function postsBySubreddit(state = {}, action) {}
您在 posts
函数中有一个初始状态,但在初始化期间不会调用它。
createStore()
中的 initialState
论点经常使人绊倒。它从来不是一种手动“初始化”应用程序状态的方式。它唯一有用的应用是:
- 从 JSON 状态负载启动服务器呈现的应用程序。
- 正在从保存到本地存储的状态“恢复”应用程序。
这意味着您永远不会手动编写 initialState
,并且在大多数应用程序中您甚至都不会使用它。相反,reducer 必须始终指定自己的初始状态,而 initialState
只是一种在您拥有现有序列化版本时预填充该状态的方法。
所以是正确的:你需要在你的reducer中定义初始状态。将它提供给 createStore()
是不够的,并且不是在代码中定义初始状态的一种方式。
我有同样的错误,但我没有包含默认情况
function generate(state={} ,action) {
switch (action.type) {
case randomNumber:
return {
...state,
random: action.payload
}
default: // need this for default case
return state
}
}
此外,请确保您在减速器中最后返回 默认状态。有时您可能会忘记确保这是您的 switch 语句的默认设置(在重构和移动代码时)。
...
default:
return state
我刚刚遇到了同样的障碍,因为我不小心在我的减速器中重新定义了 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;
为了解决这个问题,我需要避免重新定义状态:
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;
tl;博士
确保:
- 您实际上是通过 action/action 创建者将数据传递给您的减速器!
- reducer 没有 return
undefined
.
例子
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;
}
}
在这种情况下,如果您不小心通过动作创建者将 undefined
传递给 action.data
,那么 react-addons-update 将 return 来自那个的 undefined
多变的。由于这会覆盖整个减速器状态,因此 return undefined
将触发错误。
调试
您可以通过检查这些地方来调试它:
- reducer 创建新状态的地方。在该部分放置一个断点以确保您没有收到或 return
undefined
那里。
- 数据传递给动作创建者的地方。
根据 redux 的文档:https://redux.js.org/basics/reducers
您需要 return 声明 switch 函数的外面
像这样:
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
}
//here you should put the return state
return state
}
确保你在最后有一个默认状态,就像这样
...
default:
return state;
对我来说,我的减速器像
import * as actions from '../actions/budgetActions';
export const initialState = {
budget: {},
loading: false,
hasErrors: false,
}
export default function budgetReducer(state = initialState, action) {
switch (action.type) {
case actions.GET_BUDGET:
return { ...state, loading: true };
case actions.GET_BUDGET_SUCCESS:
return { budget: action.payload, loading: false, hasErrors: false };
case actions.GET_BUDGET_FAILURE:
return { ...state, loading: false, hasErrors: true };
}
}
而不是(我错过了默认案例)
import * as actions from '../actions/budgetActions';
export const initialState = {
budget: {},
loading: false,
hasErrors: false,
}
export default function budgetReducer(state = initialState, action) {
switch (action.type) {
case actions.GET_BUDGET:
return { ...state, loading: true };
case actions.GET_BUDGET_SUCCESS:
return { budget: action.payload, loading: false, hasErrors: false };
case actions.GET_BUDGET_FAILURE:
return { ...state, loading: false, hasErrors: true };
default:
return state;
}
}
const firstReducer = (state = 0) => {
switch (0) {
case 0:
return state + 1;
default:// add this default in user reducer functions
return state;
} }; export default firstReducer;
我已经在我的 redux createStore 方法中设置了 InitialState,并且我相应的 InitialState 作为第二个参数
我在浏览器中遇到错误:
<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>
代码在这里:
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
并且我在 Root.js
中调用了 configeStore
方法:
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>
)
}
}
但我猜这个 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
但是如果我在我的每个子减速器中设置 initialState
它可以正常做词。有问题?
当你的减速器第一次被调用时,状态是未定义的。然后您必须 return 初始状态(这就是错误消息告诉您的内容)。 定义初始状态值的通常方法是为状态参数设置一个默认值:
function postsBySubreddit(state = {}, action) {}
您在 posts
函数中有一个初始状态,但在初始化期间不会调用它。
createStore()
中的 initialState
论点经常使人绊倒。它从来不是一种手动“初始化”应用程序状态的方式。它唯一有用的应用是:
- 从 JSON 状态负载启动服务器呈现的应用程序。
- 正在从保存到本地存储的状态“恢复”应用程序。
这意味着您永远不会手动编写 initialState
,并且在大多数应用程序中您甚至都不会使用它。相反,reducer 必须始终指定自己的初始状态,而 initialState
只是一种在您拥有现有序列化版本时预填充该状态的方法。
所以createStore()
是不够的,并且不是在代码中定义初始状态的一种方式。
我有同样的错误,但我没有包含默认情况
function generate(state={} ,action) {
switch (action.type) {
case randomNumber:
return {
...state,
random: action.payload
}
default: // need this for default case
return state
}
}
此外,请确保您在减速器中最后返回 默认状态。有时您可能会忘记确保这是您的 switch 语句的默认设置(在重构和移动代码时)。
...
default:
return state
我刚刚遇到了同样的障碍,因为我不小心在我的减速器中重新定义了 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;
为了解决这个问题,我需要避免重新定义状态:
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;
tl;博士
确保:
- 您实际上是通过 action/action 创建者将数据传递给您的减速器!
- reducer 没有 return
undefined
.
例子
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;
}
}
在这种情况下,如果您不小心通过动作创建者将 undefined
传递给 action.data
,那么 react-addons-update 将 return 来自那个的 undefined
多变的。由于这会覆盖整个减速器状态,因此 return undefined
将触发错误。
调试
您可以通过检查这些地方来调试它:
- reducer 创建新状态的地方。在该部分放置一个断点以确保您没有收到或 return
undefined
那里。 - 数据传递给动作创建者的地方。
根据 redux 的文档:https://redux.js.org/basics/reducers
您需要 return 声明 switch 函数的外面 像这样:
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
}
//here you should put the return state
return state
}
确保你在最后有一个默认状态,就像这样
...
default:
return state;
对我来说,我的减速器像
import * as actions from '../actions/budgetActions';
export const initialState = {
budget: {},
loading: false,
hasErrors: false,
}
export default function budgetReducer(state = initialState, action) {
switch (action.type) {
case actions.GET_BUDGET:
return { ...state, loading: true };
case actions.GET_BUDGET_SUCCESS:
return { budget: action.payload, loading: false, hasErrors: false };
case actions.GET_BUDGET_FAILURE:
return { ...state, loading: false, hasErrors: true };
}
}
而不是(我错过了默认案例)
import * as actions from '../actions/budgetActions';
export const initialState = {
budget: {},
loading: false,
hasErrors: false,
}
export default function budgetReducer(state = initialState, action) {
switch (action.type) {
case actions.GET_BUDGET:
return { ...state, loading: true };
case actions.GET_BUDGET_SUCCESS:
return { budget: action.payload, loading: false, hasErrors: false };
case actions.GET_BUDGET_FAILURE:
return { ...state, loading: false, hasErrors: true };
default:
return state;
}
}
const firstReducer = (state = 0) => {
switch (0) {
case 0:
return state + 1;
default:// add this default in user reducer functions
return state;
} }; export default firstReducer;