JJ F
JJ F

Reputation: 1549

Why redux reducer getting 'undefined' instead of the initial state?

I create a toy example with NodeJS and redux. I create a store like this:

var initialState = {config: defaultConfig, customData: data};
const store = createStore(reducers, initialState)

I make sure defaultConfig and data are defined, i.e. i really stop the debugger before the statement and I can confirm the config is really there. However, inside the reducers, the state is undefined. Why?!

The reducers are:

const configReducer = (config: any, action: any): any =>{
        return config;
}

const customData = (customData: any, action: any): any =>  {
        return customData;
}
const reducers = combineReducers({config: configReducer, customData: customDataReducer})

So I am explicitly giving an initial state, but redux will call the reducers with undefined.

I know I could put the initial state as default parameter in the reducers, or use any other work around. That is not the question here.

The question is: why this is not working if I pass the initial state when building the store.

Upvotes: 6

Views: 12116

Answers (5)

zemil
zemil

Reputation: 5118

In my case I used redux-persist and it returned old state of slice.

So just clear storage you use:

localStorage.clear();

Upvotes: 2

Niraj
Niraj

Reputation: 793

I faced same issue and while I debugged the code it will be your object with key because each state maintained separate object.

const reducers = combineReducers({config: configReducer, customData: customDataReducer})

Here when you get data with undefined by default your state is like

{config:undefined, customData:undefinded}

Why??: Because combineReducer function has an option to provide initial state to each key or say separate states like below otherwise optional to pass initial state with undefined by default

    const initialRootState={config:{}, customData:{}};
    const reducers = combineReducers({config: configReducer, 
                     customData: customDataReducer});

    const store= createStore(reducers,initialRootState);

Now when your reducer initialized state with default case

 export default function configReducer(state = initialState, action){}
    //state = initialState even undefined called
 export default function customDataReducer(state = initialState, action){}
    //state = initialState even undefined called

But it will return undefined due to normal behavior of combineReducers function to pass your initial state with default "undefined" {config:undefined, customData:undefinded} and your state object will look like state:{config:{initialState}} for configReducer state:{customData:{initialState}} for customDataReducer

Upvotes: 1

Anthony Medina
Anthony Medina

Reputation: 43

if you're getting undefined, then replace it... in my case, when my server reply without the data for any reason, maybe because there is not active session, I got that problem, so doing this in the reducer, worked as a charm for me:

export default function itemReducer(state = initialState.items | undefined, action){ 
    switch(action.type) 
   { 
         case "LOAD_ITEMS_SUCCESS":
               if(action.items==undefined) { 
                        action.items=[]; 
               }
                return action.items

If the reducer gets undefined, then replace undefined for an empty array, and you won't get that error anymore.

Cheers!

Upvotes: 0

Sudhir Patil
Sudhir Patil

Reputation: 11

Giving initial state while creating store will not initialise your store. You have to explicitly set initial state in reducers.

Please refer Why do I get “Reducer [...] returned undefined during initialization” despite providing initialState to createStore()?

Upvotes: 1

Estus Flask
Estus Flask

Reputation: 223114

This behaviour is specific to combineReducers:

Any reducer passed to combineReducers must satisfy these rules:

  • For any action that is not recognized, it must return the state given to it as the first argument.

  • It must never return undefined. It is too easy to do this by mistake via an early return statement, so combineReducers throws if you do that instead of letting the error manifest itself somewhere else.

  • If the state given to it is undefined, it must return the initial state for this specific reducer. According to the previous rule, the initial state must not be undefined either. It is handy to specify it with ES6 optional arguments syntax, but you can also explicitly check the first argument for being undefined.

With combineReducers, a reducer is initially called with undefined to assert that it doesn't break these rules. Only then it will be called with initialState.

So initialState is intended to hydrate the state with initial values, not provide default values.

A reducer should be able to handle unexpected state on unexpected action (default clause in switch), in this case initial value should be forcedto be anything but undefined, e.g.:

const configReducer = (config: any = null, action: any): any =>{
        return config;
}

const customData = (customData: any = null, action: any): any =>  {
        return customData;
}

Upvotes: 3

Related Questions