Lazy Loading with React + Redux and Webpack 2

Rubens Pinheiro Gonçalves Cavalcante
Frontend Weekly
Published in
4 min readSep 26, 2017
Picture under the Creative Commons license (source: https://goo.gl/VpKoAZ)

Note I: This is a follow up for the Lazy Loading with React and Webpack 2. As this will use the previously example, it will require that you read it do understand entirely this article.

Note II: As this article uses some concepts of Redux in the examples, it’s essential that you know how it works to fully understand what is being done.

Adding Redux to the equation

Redux uses the concept of a unique application state, represented by the store. By definition:

“A store holds the whole state tree of your application.
The only way to change the state inside it is to dispatch an action on it.”

So, as a centralized singleton representing the app state, how we’re going to work with it if we’re trying to break our app in small and, mostly, independent modules? This makes our work a little more complicated, right?

But, If you think in your app also as a tree of features, represented by your modules, and being lazily loaded, we can do the very same to the state tree. For instance, the instant you access a feature, e.g. “Products”, and this feature is injected as part of you application tree, we can inject this substate to the state tree too.

🤓 “This makes no sense! The store is configured on the application bootstrap. How you’re going to do it?”

Simple, we going to create a way to asynchronously register new substates + reducers!

The Async Store

To register new reducers in runtime, we’re going to make use of the replaceReducer method. In this Stack Overflow question, Dan Abramov explains how to async register new reducers. Let’s follow his example but doing some small modifications, just to be more simple.

Note III: I’m using redux-thunk just to be more simple on the examples, but you can use sagas, epics or other middlewares.

Note IV: As in this example we’re using the object spread notation, you’ll need to install the “babel-plugin-transform-object-rest-spread”.

First I export the store as default, simply using a IIFE as a factory, using a utility function “createReducer”, where we define the very first reducer, which does nothing. But it’s important just to setup the bare setup of our store/state. Also we define here the property “async” just to store the sub reducers which are going to be async. defined.

Note, the important part of this code is the “registerReducer”. There we actually set new reducers (on the async property) and the substitutes the main one with it. This way, we never lose data.

🤓 “Nice, what I do with it now? In the previous post we’ve exposed only the Component inside the module. And more, we load it inside another, the AsyncComponent. I don’t think is right to register reducers inside Components, mixing the stuff and making it confusing!”

You’re 100% right! That’s why we need to refactor that code and detach this responsibility from the AsyncComponent. We need a way to register the modules loaded in our app, exposing the Component and whatever is inside of it and also, trigger the reducer registering, using our above example function: registerReducer. Let’s maintain the convention and expose the reducer as “reducer”.

Now, we create the module register:

We’re going to use the module context, to store and register any previously resolved/loaded modules. It checks if the moduleProvider was already registered, and if not, simply extract the reducer from it and call the reducer registration.

The good thing is, because it acts like a setter/getter of modules, if you need expose more things to use in other features, like action creators, you can. Just remember to create your modules to be as independent as you can, so if you’re using action creators from other modules, they should be moved to a commons module or something similar.

🤓 “Interesting… But now we’re going to refactor a lot of stuff because the async loading behaviour was attached to the AsyncComponent, right?”

  • We’re going to refactor ✔correct!
  • … a lot of stuff ✗wrong!

The only change is on the root App component, we’re going to invoke the module register factory using the store and then, register all the modules using this function. Remember last time we simply created functions which returned the module Promises. Now, we do the pretty same, but the module register acts like a middleware, injecting the module reducer and the resolving the module. That’s why we don’t need change one single line of the AsyncComponent!

🤓 “Hey, after all, that wasn’t soooo hard!”

Yes, small modifications here and there, and is finally working!

🤓 “I’m crying now …”

Live example

As the previous post, I’ll let a live example here, so you can test it by yourself. Note, to see the reducer being async. loaded you’re going to need the “redux-dev-tools” extension, available for Chrome and Firefox.

Conclusion

The good thing on Redux is because it’s very versatile and we can adapt it to our needs (as we did), of course without modifying the main behaviour.

If you liked this article give it some claps 👏 and share it! Depending on the feedback I’ll do another follow up (I was thinking on add some reactive programing concepts with RxJS), but is your call! Thanks for reading!

--

--