Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 697
Jose Avatar asked Oct 27 '18 04:10

Jose


People also ask

Why is Redux state undefined?

When Redux initializes it dispatches a "dummy" action to fill the state. So your counter reducer was called with state equal to undefined . This is exactly the case that "activates" the default argument. Therefore, state is now 0 as per the default state value ( state = 0 ).

How do I set Redux state to initial state?

You can set it at the reducers . Reducers can also set initialState by looking at the incoming state argument (which would be undefined if createStore is not called with initialState ) and returning the values they would like to use as default.

In what condition a reducer can return undefined?

Reducer "blogTypeVisibilityFilter" 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. If you don't want to set a value for this reducer, you can use null instead of undefined.

Do reducers need initial state compulsorily?

In a nutshell: it's Redux the one who passes the initial state to the reducers, you don't need to do anything.

What is a reducer in Redux?

Reducers are functions that take the current state and an action as arguments, and return a new state result. In other words, (state, action) => newState. A Redux app really only has one reducer function: the "root reducer" function that you will pass to createStore later on.

Why is the initial state of my reducer undefined?

The initial state is zero. Why? Because the second argument to createStore was undefined. This is the state passed to your reducer the first time. When Redux initializes it dispatches a "dummy" action to fill the state. So your counter reducer was called with state equal to undefined.

What is the use of Redux in react?

In ReactJS, redux is the tool for the management of the state throughout the whole application globally. The state that we use inside redux as a store can only be modified with the help of the actions. But, this state must be specified somewhere first to use it. We prefer to declare our initial state at the reducer files.

How to modify the state of a redux store?

The state that we use inside redux as a store can only be modified with the help of the actions. But, this state must be specified somewhere first to use it. We prefer to declare our initial state at the reducer files. Then we use that reducer in the store and provide that store use inside the whole application.


1 Answers

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;
}
like image 100
Estus Flask Avatar answered Oct 11 '22 21:10

Estus Flask