Search code examples
javascriptnode.jsreactjsredux

cannot set initial state in Redux


Despite the abundance of the same question on Stackoverflow, I haven't found a proper answer to my problem. I have previously tried the 2 methods, to set the initial state into the reducers first argument as default value const reducer(state = initialStateObj, action) and the 2nd method as 2nd argument into the createStore method, e.g. createStore(reducer, initialStateObj) but nothing seems to work, as result getting a NodeJs error on running the index.js file.

Combined reducers or with a single reducer, the initial state is always undefined.

Also I have noticed the 'throw shapeAssertionError;' and I have research it [https://stackoverflow.com/questions/49193305/how-to-fix-shapeassertionerror-while-using-combinereducer-in-redux][1] but from this later thread results that I am initializing correctly the initial state.

Where I am doing the mistake ?

package.json

{
  "name": "redux_demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "redux": "^4.0.5"
  }
}

index.js

const redux = require('redux');
const createStore = redux.createStore; 
const combineReducers = redux.combineReducers;

const BUY_CAKE = 'BUY_CAKE';
const BUY_ICECREAM = 'BUY_ICECREAM';


// buyCake() - action creator
function buyCake() {
    return {
        type: BUY_CAKE,
        info: 'First redux action'
    }
}

function buyIceCream() {
    return {
        type: BUY_ICECREAM        
    }
}

// (prevState, action) => newState
const initialCakeState = {
    numOfCakes: 10
}

const initialIceCreamState = {
    numOfIceCreams: 20
}


const cakeReducer = (state = initialCakeState, action) => {
    switch(action.type) {
        case BUY_CAKE: return {
            ...state,
            numOfCakes: state.numOfCakes - 1
        }

        default: state
    }

}

const iceCreamReducer = (state = initialIceCreamState, action) => {
    switch(action.type) {
            case BUY_ICECREAM: return {
            ...state,
            numOfIceCreams: state.numOfIceCreams - 1
        }

        default: state
    }

}
const rootReducer = combineReducers({
    cake: cakeReducer,
    iceCream: iceCreamReducer
})
const store = createStore(rootReducer)
// const store = createStore(cakeReducer, initialCakeState)
console.log('state ' + JSON.stringify(store.getState()))
const unsubscribe = store.subscribe(() => console.log('Updated state ' + JSON.stringify(store.getState())));
store.dispatch(buyCake())
store.dispatch(buyCake())
store.dispatch(buyCake())
store.dispatch(buyIceCream())
store.dispatch(buyIceCream())
unsubscribe()

error

adrian@addlandia:~/projects/redux_demo$ node index.js
/home/adrian/projects/redux_demo/node_modules/redux/lib/redux.js:447
      throw shapeAssertionError;
      ^

Error: Reducer "cake" 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.
    at /home/adrian/projects/redux_demo/node_modules/redux/lib/redux.js:378:13
    at Array.forEach (<anonymous>)
    at assertReducerShape (/home/adrian/projects/redux_demo/node_modules/redux/lib/redux.js:371:25)
    at combineReducers (/home/adrian/projects/redux_demo/node_modules/redux/lib/redux.js:436:5)
    at Object.<anonymous> (/home/adrian/projects/redux_demo/index.js:56:21)
    at Module._compile (internal/modules/cjs/loader.js:999:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
    at Module.load (internal/modules/cjs/loader.js:863:32)
    at Function.Module._load (internal/modules/cjs/loader.js:708:14)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12)
adrian@addlandia:~/projects/redux_demo$ ```


  [1]: https://stackoverflow.com/questions/49193305/how-to-fix-shapeassertionerror-while-using-combinereducer-in-redux

Solution

  • You need to return the state from the reducer, not just compute it. Change your reducers to e.g.:

    const cakeReducer = (state = initialCakeState, action) => {
        switch(action.type) {
            case BUY_CAKE: return {
                ...state,
                numOfCakes: state.numOfCakes - 1
            }
    
            default: return state
        }
    
    }
    
    

    You don't return the default state from any reducer, this is what the error says too :)