Ever since I first got to use React Loadable and React Lazy and Suspense, I've been a big advocate of route base code splitting for big applications. They allow the client to only load the chunks of the apps they are actually accessing instead of having to download the whole app before rendering something on the screen. It works so well that this pattern is even featured on the official documentation of the React Library. However, I'm always looking for tips and tricks on how I could make the end-user experience even better and that's why recently I've been trying to address the problem of how to preload chunks in a route base code split React app to make navigation between chunks more seamless. I've seen this behavior on some Gatsby sites and I really liked how discrete and efficient it is. That's why I decided to write my own take on implementing preloading and to share it with you all!

Note: I based this implementation on react-router-dom and react 16.8.0 or later. The code featured for this post is available here

Our app Let's consider a React app with multiple routes: a landing page route, another one to get a list of todos, another one to inspect todos. Each route renders a specific view / components. We carefully read the React documentation about code splitting and used React.Lazy and React.Suspense which results in us having a codebase similar to the following: Sample route based code split app root javascript Copy 1 import React from 'React' ; 2 import { Route , Router , Switch } from 'react-router-dom' ; 3 4 const App = React . lazy ( ( ) => import ( './App' ) ) ; 5 const Todos = React . lazy ( ( ) => import ( './Todos' ) ) ; 6 const Todo = React . lazy ( ( ) => import ( './Todo' ) ) ; 7 8 const routes = [ 9 { path : '/' , exact : true , component : App } , 10 { path : '/todos' , exact : true , component : Todos } , 11 { path : '/todos/:id' , exact : true , component : Todo } , 12 ] ; 13 14 ReactDOM . render ( 15 < Router > 16 < React . Suspense fallback = { 'Loading' } > 17 < Switch > 18 { routes . map ( route => ( 19 < Route 20 key = { route . path } 21 exact = { route . exact } 22 path = { route . path } 23 component = { route . component } 24 / > 25 ) ) } 26 < / Switch > 27 < / React . Suspense > 28 < / Router > 29 ) ; If we run our app, we can see in the developer tools of our browser that navigating from one view to another is loading the different "pieces" or "chunks" of our app. Now let's focus on how we could start loading these chunks when the user hovers one of the navigation links instead of loading them after navigating to the new route.

Preload components with React Lazy To preload the view we'll have to be able to call a preload method on our chunk. This preload method would be able to be called to run the import statement that is passed to React Lazy. While such functionality is available out of the box in React Loadable, React Lazy doesn't seem to provide it and this is why we'll have to implement it from scratch with the following code: Implementation of ReactLazyPreload javascript Copy 1 const ReactLazyPreload = importStatement => { 2 const Component = React . lazy ( importStatement ) ; 3 Component . preload = importStatement ; 4 return Component ; 5 } ; We can now redeclare our code split chunks as follows: Examples of usage of ReactLazyPreload javascript Copy 1 const App = ReactLazyPreload ( ( ) => import ( './App' ) ) ; 2 3 const Todos = ReactLazyPreload ( ( ) => import ( './Todos' ) ) ; 4 5 const Todo = ReactLazyPreload ( ( ) => import ( './Todo' ) ) ; With the code above we can now call the preload method at will on any of our components which will result in each of them loading their respective chunks: Calling "preload" on our components javascript Copy 1 App . preload ( ) ; 2 Todos . preload ( ) ; 3 Todo . preload ( ) ;