Почему я получаю сообщение «Reducer [] вернул неопределенное значение во время инициализации», несмотря на предоставление initialState для createStore()?

Я установил InitialState в моем методе createStore с редукцией, и я соответствую 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

и я вызвал configeStoremethod в 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>
  )
 }
}

но я предполагаю, что у этого 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 в каждом моем подчиненном редукторе, он может нормально работать. Что-то не так?


person Ice Wilder    schedule 14.04.2016    source источник


Ответы (10)


Аргумент initialState в createStore() часто сбивает людей с толку. Это никогда не предназначалось для «инициализации» состояния вашего приложения вручную. Единственными полезными приложениями для него являются:

  • Загрузка приложения, отображаемого сервером, из полезных данных состояния JSON.
  • «Возобновление» приложения из состояния, сохраненного в локальном хранилище.

Подразумевается, что вы никогда не пишете initialState вручную и в большинстве приложений даже не используете его. Вместо этого редукторы всегда должны указывать свое собственное начальное состояние, а initialState — это просто способ предварительного заполнения этого состояния, когда у вас есть существующая сериализованная версия.

Итак, этот ответ правильный: вам нужно определить начальное состояние в вашем редукторе. Предоставления его createStore() недостаточно, и он не предназначен для определения начального состояния в коде.

person Dan Abramov    schedule 15.04.2016
comment
Кажется, это противоречит описанию в документации Redux: redux.js.org/docs/ recipes/reducers/InitializingState.html - person martin; 25.06.2017
comment
Из редукс-документов All reducers are passed undefined on initialization, so they should be written such that when given undefined - person aks; 07.08.2017
comment
Ответ @aks на самом деле более уместен. У меня была аналогичная проблема, но, вероятно, вызванная той же проблемой. Я обнаружил, что редукторы должны обрабатывать состояния undefined в качестве параметра и в этих случаях должны возвращать начальное состояние, как указано в документации по редуксу. - person Giulio G.; 18.06.2021

У меня была такая же ошибка, но я не включил случай по умолчанию

function generate(state={} ,action) {
  switch (action.type) {
    case randomNumber:
      return {
        ...state,
        random: action.payload
      }   
    default: // need this for default case
      return state 
   }
}
person Isaac Pak    schedule 06.10.2017
comment
Да! Это была моя проблема. - person Rob Grant; 22.10.2017
comment
Обычно Эслинт или Претье замечали, что у меня нет дела по умолчанию. Так что спасибо тебе! Это легко упустить из виду. - person Karl Taylor; 03.03.2018
comment
Да, я забыл добавить случай по умолчанию. Спасибо. - person Allan Mwesigwa; 02.05.2018
comment
И я вернулся, и да, это снова решило это. Я должен перестать что-то забывать. - person Rob Grant; 02.02.2019
comment
Это была и моя проблема. - person iaq; 23.02.2020
comment
он же спасатель! - person Edwin O.; 19.04.2021

Кроме того, убедитесь, что вы возвращаете состояние по умолчанию последним в редюсере. Иногда вы можете забыть убедиться, что это значение по умолчанию для вашего оператора switch (при рефакторинге и перемещении кода).

...
 default:
  return state
person TechnoTim    schedule 29.12.2017
comment
СПАСИБО! Это было абсолютным спасением жизни. Не могу сказать это достаточно. - person anon58192932; 26.07.2019
comment
Без проблем! Я даже получил этот же ответ по той же проблеме при использовании моей собственной копировальной пасты, которая является избыточными действиями;) - person TechnoTim; 29.07.2019

Когда ваши редукторы вызываются в первый раз, состояние не определено. Затем вы должны вернуть исходное состояние (об этом говорит вам сообщение об ошибке). Обычный способ определения начального значения состояния — установить значение по умолчанию для параметра состояния:

function postsBySubreddit(state = {}, action) {}

У вас есть начальное состояние в функции posts, но оно не вызывается во время инициализации.

person Florian Cargoet    schedule 14.04.2016
comment
но у меня есть начальное состояние в методе createStore для вторых аргументов - person Ice Wilder; 14.04.2016
comment
Ты прав. Похоже, что один из ключей не соответствует редюсеру: selectedsubreddit => selectedSubreddit. Может ли это быть источником ошибки? - person Florian Cargoet; 14.04.2016
comment
Утром работает нормально, а днем ​​не работает и браузер выдает ту же ошибку. Я никогда не меняю свой код, но он все равно показывает ту же ошибку - person Ice Wilder; 15.04.2016

Я столкнулся с той же проблемой, потому что случайно переопределил 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;
person duhaime    schedule 02.01.2018

согласно документации redux: https://redux.js.org/basics/reducers

вам нужно вернуть состояние вне функции переключателя следующим образом:


 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
}
person Khorram Bin Salim Khondkar    schedule 01.08.2020
comment
если мы вернем состояние вне оператора switch, оно станет недоступным - person james; 05.11.2020
comment
хм, я следил за документацией. Сейчас, наверное, обновился. Спасибо, что заметили - person Khorram Bin Salim Khondkar; 30.12.2020

tl;dr

Убедись, что:

  • На самом деле вы передаете данные своему редюсеру через создателя действия/действия!
  • Редуктор не возвращает 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 вернет undefined из этой переменной. Поскольку это перезаписывает все состояние редуктора, он вернет тот undefined, который вызовет ошибку.

Отладка

Вы можете отладить это, изучив эти места:

  • Где редуктор создает новое состояние. Поместите точку останова в эту часть, чтобы убедиться, что вы не получите и не вернете undefined там.
  • Где данные передаются создателю действия.
person totymedli    schedule 08.02.2019

убедитесь, что у вас есть состояние по умолчанию в конце, например так

...
default:
  return state;
person Edwin O.    schedule 18.04.2021

В моем случае я использую React + typescript, поэтому у меня была эта ошибка

Если состояние, переданное редюсеру, не определено, вы должны явно вернуть начальное ›состояние. Начальное состояние не может быть неопределенным. Если вы не хотите устанавливать значение для этого редьюсера, вы можете использовать null вместо undefined.

А проблема была в том, что мой редуктор был таким (упрощу):

export const authReducer = (state : {}, action: ActionType) => {}

и это должно было быть

export const authReducer = (state = {}, action: ActionType) => {}
person Matias Hamie    schedule 10.02.2021

export const authReducer = (state = {}, action: ActionType) => {}

Не ставьте ':' после того, как это вызывает ошибку, вместо этого поставьте знак равенства '=' после того, как вы инициализируете состояние в параметре authReducer

person Umer Waseem    schedule 16.07.2021
comment
Привет, Умер, кажется, вы даете ответ на TypeScript, но в вопросе не используется TypeScript, а только ванильный JavaScript. - person MickelsonMichael; 17.07.2021
comment
Да я знаю, я поделился только конкретной проблемой - person Umer Waseem; 20.07.2021