web-dev-qa-db-fra.com

Pourquoi est-ce que je reçois "Réducteur [...] renvoyé non défini lors de l'initialisation" alors que initialState était fourni à createStore ()?

J'avais initialisé InitialState dans ma méthode redux createStore, et InitialState correspondant comme second argument 

J'ai une erreur dans le navigateur:

<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>

le code est ici:

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

et j'ai invoqué configeStoremethod dans 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>
  )
 }
}

mais je suppose que cette initateState a quelque chose qui cloche:

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

mais si je mets initialState dans chacun de mes sous-réducteurs, il peut faire Word normalement. Quelque chose ne va pas? 

44
Ice Wilder

L'argument initialState dans createStore() fait souvent trébucher les gens. Cela n'a jamais été conçu comme un moyen «d'initialiser» votre état d'application manuellement. Les seules applications utiles pour cela sont:

  • Démarrage de l'application rendue par le serveur à partir de la charge utile de l'état JSON.
  • «Reprendre» l'application à partir d'un état enregistré dans la mémoire de stockage locale.

Cela signifie que vous n'écrivez jamais initialState manuellement et que vous ne l'utilisez même pas dans la plupart des applications. Au lieu de cela, les réducteurs doivent toujours spécifier leur propre état initial, et initialState est simplement un moyen de pré-remplir cet état lorsque vous en avez une version sérialisée existante.

Donc cette réponse est correcte: vous avez besoin pour définir l’état initial dans votre réducteur. Le fournir à createStore() n'est pas suffisant et ne constitue pas un moyen de définir l'état initial dans le code.

63
Dan Abramov

J'ai eu la même erreur mais je n'ai pas inclus de cas par défaut

function generate(state={} ,action) {
  switch (action.type) {
    case randomNumber:
      return {
        ...state,
        random: action.payload
      }   
    default: // need this for default case
      return state 
   }
}
27
Isaac Pak

Lorsque vos réducteurs sont appelés pour la première fois, l'état n'est pas défini. Vous devez ensuite renvoyer l'état initial (c'est ce que vous dit le message d'erreur). La manière habituelle de définir la valeur d'état initiale consiste à définir une valeur par défaut pour le paramètre d'état:

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

Vous avez un état initial dans la fonction posts mais il n'est pas appelé lors de l'initialisation. 

23
Florian Cargoet

Assurez-vous également que vous avez renvoyé l'état par défaut en dernier dans votre réducteur. Parfois, vous pouvez oublier de vous assurer que c'est la valeur par défaut pour votre instruction switch (lors du refactoring et du déplacement de code).

...
 default:
  return state
8
TechnoTim

Je viens de toucher le même problème parce que j'ai redéfini accidentellement state dans mon réducteur:

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;

Pour résoudre le problème, je devais m'abstenir de redéfinir l'état:

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;
3
duhaime

tl; dr

Sois sûr que:

  • En fait, vous transmettez des données à votre réducteur via l'action/action creator!
  • Le réducteur ne renvoie pas undefined.

Exemple

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;
  }
}

Dans ce cas, si vous passez accidentellement undefined à action.data via votre créateur d'action, alors react-addons-update renverra la undefined provenant de cette variable. Etant donné que ceci écrase tout l’état du réducteur, la variable undefined qui déclenchera l’erreur sera renvoyée.

Débogage

Vous pouvez résoudre ce problème en examinant ces endroits:

  • Où le réducteur crée le nouvel état. Placez un point d'arrêt dans cette partie pour vous assurer de ne pas recevoir ou renvoyer undefined.
  • Où les données sont transmises au créateur de l'action.
0
totymedli