Blog>
Snippets

Lazy Loading Reducers with UnknownAction

Explain how to code split reducers and use UnknownAction to re-initialize the store when a new reducer is loaded asynchronously.
// Define an action type for when we don't recognize the action
const UNKNOWN_ACTION = 'UNKNOWN_ACTION';

// Initial state for the reducer
const initialState = {};

// Placeholder reducer that does nothing but return the current state
function unknownReducer(state = initialState, action) {
  switch (action.type) {
    case UNKNOWN_ACTION:
      return state;
    default:
      return state;
  }
}
This piece of code sets up a basic reducer that responds to an 'UNKNOWN_ACTION'. Whenever an unknown action is dispatched, this reducer will simply return the current state, effectively doing nothing.
function createReducer(asyncReducers) {
  return combineReducers({
    ...asyncReducers
    // other synchronous reducers can be added here
  });
}

// A function to store a reference to the store's dispatch
let dispatch;

// Configure the store with the initial combined reducer
// It doesn't include any asynchronously loaded reducers yet
const store = createStore(createReducer(), applyMiddleware(thunk));

dispatch = store.dispatch;

// This function allows us to add asynchronously loaded reducers
function injectReducer(key, asyncReducer) {
  store.asyncReducers[key] = asyncReducer;
  store.replaceReducer(createReducer(store.asyncReducers));
  // Dispatch an unknown action to reinitialize the store
  dispatch({ type: UNKNOWN_ACTION });
}
This code sets up a store and a function to inject reducers asynchronously. The createReducer function combines the initially synchronous reducers with any that are loaded later. The injectReducer function adds the new reducer and calls replaceReducer on the store to use the updated set of reducers. An unknown action is dispatched to reinitialize the store to ensure that the new reducer receives an initial state.
// Example usage of the injectReducer function
// Assume we have an asyncReducer that we want to lazy-load

// We might call this function in response to a route change or other event
const loadAsyncReducer = () => {
  import('./pathToReducerFile').then(module => {
    const asyncReducer = module.default;
    injectReducer('asyncReducerKey', asyncReducer);
  });
};
This code demonstrates how to use the injectReducer function to load a reducer asynchronously. The loadAsyncReducer function is called to lazy-load a reducer module which, once loaded, is injected into the store using the injectReducer function.
<!DOCTYPE html>
<html>
<head>
  <title>Lazy Loading Reducers Example</title>
</head>
<body>
  <!-- Trigger the lazy loading of a reducer -->
  <button onclick="loadAsyncReducer()">Load Reducer</button>

  <script src="pathToBundle.js"></script>
</body>
</html>
This HTML markup provides a simple webpage with a button. When clicked, the button triggers the lazy loading of a reducer by invoking the loadAsyncReducer function. This code assumes that the JavaScript necessary for lazy loading reducers is bundled into 'pathToBundle.js'.