Search code examples
javascriptreactjsreduxreact-boilerplate

Modify react-boilerplate to nest injected reducers under a single key of the store


react-boilerplate has a utility injectReducer that is used to allow a reducer to be asynchronously attached to the store, and in the reducers.js file for the entire application, createReducer spreads out these injectedReducers into the state so that you have a state shape as follows:

{
  route: routeReducer,
  language: languageProviderReducer,
  container1: container1Reducer,
  container2: container2Reducer,
  container3: container3Reducer,
}

I would like instead to spread out these container-specific reducers to a subkey of the global state like so:

{
  route: routeReducer,
  language: languageProviderReducer,
  ui: {
    container1: container1Reducer,
    container2: container2Reducer,
    container3: container3Reducer,
  }
}

I naively tried to modify the reducers.js method createReducer like so:

export default function createReducer(injectedReducers) {
  return combineReducers({
    route: routeReducer,
    language: languageProviderReducer,
    ui: (injectedReducers) ? combineReducers(injectedReducers) : ((state = {}) => state),
  });
}

or maybe:

export default function createReducer(injectedReducers) {
  return combineReducers({
    route: routeReducer,
    language: languageProviderReducer,
    ui: combineReducers(injectedReducers || {}),
  });
}

But now when I try to load any container, I get an error: TypeError: Cannot read property '_currentElement' of null.

What is the easiest path to achieve the kind of state shape I want using injected reducers and react-boilerplate?


Solution

  • The key for me I believe was to only add the ui key when it was needed (when at least one injectedReducers was present).

    /**
     * Creates the main reducer with the dynamically injected ones
     */
    export default function createReducer(injectedReducers) {
      const reducersToCombine = {
        form: formReducer,
        language: languageProviderReducer,
        route: routeReducer,
      };
    
      if (injectedReducers && Object.keys(injectedReducers).length > 0) {
        reducersToCombine.ui = combineReducers(injectedReducers);
      }
    
      return combineReducers(reducersToCombine);
    }