简体   繁体   中英

Redux preloadedState causing override (and subsequent undefined error) of default reducer state?

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, preloadedState always wins over state = ... in the reducer because the state passed to the reducer is preloadedState and is not undefined , so the ES6 argument syntax doesn't apply.

With combineReducers() the behavior is more nuanced. Those reducers whose state is specified in preloadedState will receive that state. Other reducers will receive undefined and because of that will fall back to the state = ... 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: []} .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM