Isomorphic Redux with code splitting and lazy loaded reducers
Asked Answered
B

1

8

I am building an isomorphic application with code splitting using react router and redux. I have gone about as far as I can, but I need some help to figure out the rest of my problem. I have a large application that requires code splitting for the front end. I have a reducer registry that enables me to register new reducers(lazy loaded), or replace existing reducers in my store. This works great, however because sections of my app are lazy loaded, my lazy loaded reducers are not present when I call combineReducers() on the client side, while they resolve perfectly on the server. This causes an unexpected keys error, and forces my store to ignore the offending key(s) in my initial state.

initialState (from server)

{ "cases": {...}, "user": {...} }

Client side redux expected initialState

This is based off of available reducers

{ "user": {...} }

Loaded Reducer

  • UserReducer

Lazy Loaded Reducer

  • CaseReducer

The error occurs when I call the following

const finalCreateStore = compose(
  applyMiddleware(promiseMiddleware)
)(createStore);
const rootReducer = combineReducers({...reducers})
const store = finalCreateStore(rootReducer, initialState);

Unexpected key "case" found in initialState argument passed to createStore. Expected to find one of the known reducer keys instead: "user". Unexpected keys will be ignored.

Everything works well on the server, but initializing the app on the client while momentarily missing a reducer until it is loaded is causing this error. Does anyone know how to get around this error, or tell redux to not validate the shape of the initial state? I need "cases" to be available to my lazy loaded reducer.

Biel answered 22/12, 2015 at 1:39 Comment(0)
D
7

It seems like you should opt not to use the built-in combineReducers, since you know the warning isn't applicable to your usage. From the Redux guide:

These two ways to write a combined reducer are completely equivalent:

const reducer = combineReducers({
  a: doSomethingWithA,
  b: processB,
  c: c
})

function reducer(state, action) {
  return {
    a: doSomethingWithA(state.a, action),
    b: processB(state.b, action),
    c: c(state.c, action)
  }
}

So you may as well go with the second option.

Dareen answered 22/12, 2015 at 2:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.