2016-04-14 12 views
22

avevo impostato InitialState nel mio metodo redux createstore e InitialState io corrispondenti come secondo argomentoPerché ottengo "Riduttore [...] restituito indefinito durante l'inizializzazione" nonostante fornisca initialState per createStore()?

ho ottenuto un errore nel navigatore:

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

codice è qui:

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 

ed io invocato il metodo configeStore in 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> 
) 
} 
} 

ma credo che questo initateState ha qualcosa che non va:

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 

ma se ho impostato initialState in ogni mia riduttore sub Può fatto parola normalmente. Qualcosa non va?

risposta

34

L'argomento initialState in createStore() spesso fa scattare le persone. Non è mai stato inteso come un modo per "inizializzare" lo stato dell'applicazione manualmente. Le uniche applicazioni utili sono:

  • Avvio di un'app resa dal server dal carico utile dello stato JSON.
  • "Riprendere" l'app da uno stato salvato nell'archivio locale.

È implicito che non si scriva mai manualmente initialState e nella maggior parte delle app non lo si usa nemmeno. Invece, i riduttori devono sempre specificare il proprio stato iniziale e initialState è solo un modo per eseguire il prefill di quello stato quando si dispone di una versione serializzata esistente.

Quindi this answer è corretto: è necessario per definire lo stato iniziale nel riduttore. Fornirlo a createStore() non è sufficiente e non intende essere un modo per definire lo stato iniziale nel codice.

+4

Questo sembra contraddire la descrizione nella documentazione di Redux: http://redux.js.org/docs/recipes/reducers/InitializingState.html – martin

+1

Da redux docs 'Tutti i riduttori sono passati non definito sull'inizializzazione, quindi dovrebbero essere scritti in modo tale che se dati indefiniti ' – aks

13

Quando i riduttori vengono richiamati per la prima volta, lo stato non è definito. È quindi necessario restituire lo stato iniziale (questo è ciò che il messaggio di errore ti dice). Il modo usuale di definire il valore dello stato iniziale è quello di impostare un valore predefinito per il parametro di stato:

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

Hai stato iniziale nella funzione posts ma non viene chiamato durante l'inizializzazione.

+0

ma ho uno stato iniziale nel metodo createStore su secondi argomenti –

+0

Hai ragione. Sembra che una delle chiavi non corrisponda al riduttore: selectedsubreddit => selectedSubreddit. Potrebbe essere la fonte di errore? –

+0

sì, è.oh mio Dio! –

8

ho avuto lo stesso errore, ma non ho incluso un caso di default

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

Sì! Questo era il mio problema –

+0

Solitamente Eslint o Prettier prendevano in considerazione il fatto che non avevo un caso predefinito. Quindi grazie! Questo è facilmente trascurato. –

2

Inoltre, assicurarsi che si sta tornando lo stato di default ultima nel riduttore. A volte puoi dimenticarti di assicurarti che questo sia l'impostazione predefinita per la tua istruzione switch (durante il refactoring e lo spostamento del codice).

... 
default: 
    return state 
0

ho appena colpito questo stesso intoppo perché per sbaglio ho ridefinito state dentro la mia riduttore:

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; 

Per risolvere il problema di cui avevo bisogno di astenersi da ridefinire Stato:

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; 
Problemi correlati