Lazy Loading and Code Splitting
In the modern era, nobody likes waiting especially for a web application to load in the browser. Over 53% of the visitors will be abandoned if the web pages take longer than 3 seconds to load. This problem occurs in the mobile environment also where the connection can be slow.
Splitting code (e.g. JavaScript) into bundles can help to overcome this problem, but you can still end up downloading a lot of data. Fortunately, it is possible by code splitting the application and allows the user to load the component lazily in whichever place they needed. This approach will improve the performance of your application.
What is Code Splitting?
Code splitting is a process of splitting code into various bundles or components which can be loaded on-demand or in parallel.
Bundling: It is the process of importing files and merging them into a single CSS, or JavaScript file, and those are grouped to create a “bundle.” This bundle can then be included on a webpage to load an entire application at once.
Why do we need Code splitting?
As the application grows in complexity, our CSS and JavaScript files or bundles will also grow as well as and the size of the included third-party libraries also increases. To prevent the requirement of downloading an enormous number of files, the scripts can be split into different multiple smaller files, which can be able to run dynamically, and it also makes the code efficient.
How to implement Code splitting?
Code-splitting is a feature supported by Webpack and Browserify. If you are using Create React App, this is configured for you, and then you can start using it at once.
The best way to introduce code-splitting into your app is through dynamic import() syntax.
App:
// greeting.js
export function sayGreeting(name, age){
return `Hi my name is ${name}. I am ${age} years old!`;
}
- Before Splitting:
// app.js
import { sayGreeting } from './greeting';
console.log(sayGreeting('Mike', 22));
- After Splitting:
// app.js
import('./greeting').then(greetingMsg => {
console.log(greetingMsg.sayGreeting('Mike', 22));
});
What is Lazy Loading in React?
Lazy loading is a common design pattern in computer programming that delays the loading of resources until they are needed by the user based on the user’s activity.
In React, we can achieve this lazy loading functionality by using React.lazy() function, and the Suspense component.
React Lazy(): It is a new function that is introduced in react from the release of version 16.6.0, and it lets you load react components lazily through code splitting without any help from any additional libraries.
Syntax for React Lazy
- Before:
import components from './someComponent';
- After:
const components = React.lazy(()=>import('./someComponent'));
Suspense: It is a mandatory component that is needed for lazy functionality because it acts as a wrapping for lazy components and multiple lazy components can be wrapped inside a single suspense component.
Why is Lazy loading (&Suspense) being important?
With code splitting, the bundle can be split into smaller files/pieces where most of the important files are loaded first, and then every other secondary one is lazily loaded. While building an application we should always be able to control the user experience during the suspense period when resources are being loaded to the DOM.
How to implement React Lazy and Suspense?
The React.lazy is a function that lets you render dynamic import as a regular component. The lazy components should be rendered inside a Suspense Component, which allows us to show some fallback content while we are waiting for the lazy components to load.
Example for React lazy and suspense
- For single Lazy components:
// app.js
import React, { Suspense } from 'react';
const greetingComponent = React.lazy(() => import('./greeting'));
function App() {
return (
<div>
<Suspense fallback={<div>Loading..Please wait..</div>}>
<greetingComponent />
</Suspense>
</div>
);
}
- For Multiple Lazy components:
// app.js
import React, { Suspense } from 'react';
const greetingComponent = React.lazy(() => import('./greeting'));
const welcomeComponent = React.lazy(() => import('./welcome'));
function App() {
return (
<div>
<Suspense fallback={<div>Loading..Please wait...</div>}>
<section>
<greetingComponent />
<welcomeComponent />
</section>
</Suspense>
</div>
);
}
Benefits of using Lazy Loading
Lazy loading can introduce many benefits to the users:
- Improves loading time
- Much better user experience
- Decreases network activity by waiting for the user to have lazily loaded elements in the viewport.
Develop a Movie listing React application that using concepts of Lazy loading & Code splitting
Let us develop a simple React application that uses Lazy loading and code splitting features. Here, I am using Create React App to create a simple boilerplate of the react application.
Note:
According to React Documentation, the webpack bundling is already configured in our project, if we use Create React App package.
- Get started:
The first step, you must install node.js on your working device. Head to the node.js website, download the LTS version and install it on your device.
- Installation: To create a React project, open the terminal and run the commands,
npx create-react-app lazy-loading-code-splitting
cd lazy-loading-code-splitting
npm start
- Development-
Folder Structure: Create a folder structure in your project as given below. And It will be great if you try to create your folder structure.
- Configuration: After the installations are finished,
- Clean up the App.js file and remove the unwanted SVG image file.
- Try to copy/paste all the .css code from the GitHub repository into their respective file in your project, because our focus is to understand the Lazy loading & Code splitting.
- Store.js: The Store.js file holds the pre-defined sets of data in the form of JSON objects. We can use this store to get some movie information and make it on their respective pages.
The server-side rendering is not yet available for React.lazy(), which is why I am using some JSON objects as a data source.
The single movie list of JSON objects looks like this, you can copy and paste the store.js file from the GitHub repository or create your own.
// store.js
export default [{
id: 1,
name: 'movie-name',
imglink: 'movie-cover-picture-link'
},{...}];
- MovieList.js & MovieCard.js: The MovieList.js file is one we can render all the movie’s details in a grid structure. We can use our store.js to pull the movie’s data from here.
// MovieList.js
import MovieCard from './MovieCard/MovieCard';
import './MovieList.css';
import MovieData from '../../store';
const MovieList = () => {
return (
<div className="movie-list">
<div className="container">
<div className="heading">
<h2>Action / Adventure</h2>
</div>
<div className="col">
{MovieData.map(movie => (
<MovieCard imglink={movie.imglink}
name={movie.name} key={movie.id} />
))}
</div>
</div>
</div>
)
}
We can send the movie’s image link and movie name as a prop to a separate component called MovieCard.
A Single movie card looks like this,
// MovieCard.js
const MovieCard = ({ imglink, name }) => {
return (
<div className="movie-card">
<img src={imglink} alt={name} />
</div>
)
}
After the configuration is done, import all the components into the App.js file.
// App.js
import { Header,MovieList } from './components';
function App() {
return (
<>
<Header />
<MovieLists />
</>
);
}
Then, run the project using these commands, and It will automatically open your default browser and show them the result.
cd lazy-loading-code-splitting
npm start
- App.js:
Let us start doing some Lazy loading, Head to App.js file and import lazy and Suspense from React like this,
import React, { Suspense, lazy } from 'react';
To render dynamic imports as a regular component, you must import that component inside a lazy function like this,
const MovieLists = lazy(
() => import('./components/MovieList/MovieList'));
function App() {
return (
<>
<Suspense>
<MovieLists />
</Suspense>
</>
);
}
The module having MovieList is not yet loaded, we must show some fallback content to the user and tell them to wait for it to load. The fallback content can be a loading message or some loading indicators brought inside the Suspense components.
After the complete configuration, the final code will look like this,
// App.js
import React, { Suspense, lazy } from 'react';
import { Header } from './components';
const MovieLists = lazy(
() => import('./components/MovieList/MovieList'));
function App() {
return (
<>
<Header />
<Suspense fallback={
<div className="loader">
<h1>Loading Movies....</h1>
</div>
}>
<MovieLists />
</Suspense>
</>
);
}
export default App;
Notes: When you are running the application on your local machine the lazy loading should be fast so you must manually slow down the network from the dev tools in the browser.
Steps to simulate:
- Open the dev tools from the browser.
- On the tabs, choose the network tab. By default, the network tab should be Online, you can switch it to slow 3G or fast 3G and run the application.
Conclusion
I hope you have learned a lot about lazy loading & code-splitting concepts by building one React application. One side note is that React.lazy() and Suspense is not available for server side-rendering. You can use a loadable component for server-rendering app code splitting.
I have attached the GitHub repository link for this movie list lazy loading application below. So please make use of it.
https://gitlab.com/fibonalabs/ui-web-blog-lazyload-codesplitting