I currently am creating a website with react-redux and was getting an error with a typo in the preloadedState variable within createStore. My relevant store code is as follows (Note the cartitems spelling in initialState instead of cartItems):
const reducer = combineReducers({
productList: productListReducer,
productDetails: productDetailsReducer,
cart: cartReducer,
})
const cartItemsFromStorage = localStorage.getItem('cartItems') ?
JSON.parse(localStorage.getItem('cartItems')) : []
//BELOW GETS PASSED INTO createStore
const initialState = {
cart: {cartitems: cartItemsFromStorage}
}
Within my cartReducer the code being affected is as follows:
export const cartReducer = (state = {cartItems: []}, action) => {
switch(action.type){
case CART_ADD_ITEM:
const item = action.payload
const existItem = state.cartItems.find(x => x.product === item.product)
***other code below...***
default:
return state
}
I noticed that this throws an Unhandled Rejection (TypeError): state.cartItems is undefined error on the existItem line. Why does the addition of the preloadedState cause this issue? From my understanding the reducer's default state (in this case given by state = {cartItems: []}) should still be accessible from within the reducer? Is this not the case?
This is by design. From the doc Initializing State:
Without
combineReducers()or similar manual code,preloadedStatealways wins overstate = ...in the reducer because the state passed to the reducer ispreloadedStateand is notundefined, so the ES6 argument syntax doesn't apply.
With
combineReducers()the behavior is more nuanced. Those reducers whose state is specified inpreloadedStatewill receive that state. Other reducers will receiveundefinedand because of that will fall back to thestate = ...default argument they specify.
For your case, the preloadedState is {cart: { cartitems: cartItemsFromStorage }}, the { cartitems: cartItemsFromStorage } object will be passed in cartReducer as it's default state rather than the ES6 default argument syntax.
That's why your cart state shape is {cartitems: cartItemsFromStorage}
If the preloadedState is undefined, then your cart default state is {cartItems: []}.