Dynamically load your redux store
What, why, how even ?
Lets first address the what — What I mean by Dynamically loading your redux store! This means we will be asynchronously loading in our redux store as users browser through our code split application. Again, what do I mean ?
Assume when someone visits www.xyz.com, this is the homepage and requires the “user” reducer of the entire redux store. So our redux store will look like:
Now thats fine, because thats all was needed for the home page, lets assume we now go to the accounts page, www.xyz.com/balance, since our code is lazy loaded, or “split”, we make an async or dynamic request to the back end to load in this new page, and when we do, our redux store is then injected with the reducer responsible for the newly loaded page. We end up with this:
Okay now that we covered the what, lets go over the why.
Why ?
Well the why is easier to explain, we are trying to reduce the load time of your application, this can obviously be done with caching but also can be done with code splitting and using redux async loading. My minimising the amount of data (Javascript )being sent to the client we ensure the code is delivered to the client faster, believe me every kiloByte matters.
Now the more important part, how ? How can you set this pattern up in your code, i’ll try my best to explain this so bare with me!
Okay, so firstly, there may be certain reducers that you need loaded at all times i.e this reducer needs to exist in the redux store regardless of a page being loaded or not, i.e its not dependant on anything. This is possible, and the second part is the async loaded reducers, so how are we doing this.
We have our main App.js file, which hosts the “parent logic” i.e this is where we go ahead and render our application to an element in our HTML.
Nothing out of the ordinary, a few missing links ofcourse, the one we’ll now look into is configureStore and what that actually does or what createRoutes does, for now, we know that configureStore is a function, that absorbs state to what we can assume will return our redux store!
Okay so what do we have here, firstly read the comments. And line 13, what we’re doing is creating an extra attribute in the store called asyncReducers, which is a an object that will house all of our, well dynamically loaded reducers, and NO we don’t need to do this.props.store.asyncReducers[storeName], and i’ll explain how we’ll avoid that problem! (hint hint, the spread operator)
But we do realise that we need to learn about this createReducer function, which again we HOPE will give us our initial reducer, well it better!
Finally, something that combines reducers and gives us our total redux store back to us!
Lets recap as to what we’ve done so far, we have our App, which takes in through a Provider some routes and our store using a configureStore method, which is invoked with an empty object. The configure store method basically creates a store with an actual reducer, a preloaded that (the empty object) and any enhancers if they exist. It also adds an asyncReducers attribute which is an object to our store before returning the store. The actual reducer is created using a createReducer function, which combines any “permanent” reducers and takes in any asyncReducers as an argument.
Phew, okay thats a fair bit, but yet makes sense, okay last two parts — we need to have a function that actually helps async injection
Again, read the comments :)
Cool so whats happening, we now use the asyncReducers attribute that was created in the configureStore method, to add an async reducer, and then we user the native replaceReducer method to pretty much “reload” the store. PS, remember how i said the asyncReducers object will be spread, well thats what happens in the createReducer method, the store.asyncReducers above are spread (read into spreading if you’re not aware). But where exactly is this function being used ?
Well that would be in a dynamic route:
so createRoutes is used for all the subRoutes, what we’re doing is using require.ensure to load in our route, the associated reducer as well, we are using callback to load the the Route and the injectAsyncReducer method to go ahead and create a reducer name, the second argument, and the associated reducer, the third argument.
And thats it folks! Hope you enjoyed it :) Please leave me any questions you’d like or thoughts you want to share!