Learn to Use Lazy Loading in React

Learn how to implement lazy loading in React and test your React code on BrowserStack for enhanced performance.

Get Started free
Home Guide Implementing Lazy Loading in React

Implementing Lazy Loading in React

By Siddharth Murugan, Community Contributor -

Lazy loading optimizes web performance by delaying the loading of non-essential elements until they are needed. These elements could be images, videos, or scripts.

If you are new to developing, you might have noticed that the loading time slows as the website grows. Lazy loading reduces this loading time. 

Lazy loading can be used across various frameworks and libraries. This article explores lazy loading in React and how to implement it.

What is Lazy Loading in React?

Lazy loading in React renders the component or webpage only when the user needs it. This can reduce the web page loading time, as the entire webpage will not be loaded when initial rendering takes place; instead, only the necessary components will be loaded.

How to Implement Lazy Loading in React?

There are several ways to implement Lazy loading in React. Here are some popular methods:

1. React.Lazy()

The first step in implementing lazy loading in React is to import the lazy feature in the React project and then try to call that for a specific component.

Import {lazy} from ‘react

const LazyComponent = lazy(() => import('./LazyComponent'));

2. Lazy loading in React using Suspense

Here’s how you can implement Lazy loading in React using Suspense.

As a first step, create a separate component named LazyComponent and let it hold an image from the src folder.

LazyComponent.js

function LazyComponent() {

   return (

       <div><img src={require('./image/elephant.jpg')}/></div>
   

   );

 }

  export default LazyComponent;

Now, inside the App.js file, you can import the LazyComponent using the React lazy function and implement it as below,

import React, {Suspense,Component} from 'react'

{/* Importing the lazy component and enabling with React.lazy function */}

const LazyComponent = React.lazy(() => import('./LazyComponent'));

class App extends Component {

 render() {

   return (

   <div className="App">

     <h1>React Lazy Loading Example</h1>

     {/* Suspense provides a fallback while the lazy component is loading */}

     <Suspense fallback={<div>Loading...</div>}>

       <LazyComponent />

     </Suspense>

   </div>

 );

 }

 }

export default App;

3. Using third-party library

There are many libraries available to implement Lazy Loading. React library introduced Lazy loading from version 16.6.

It didn’t have such a feature before that. When that was the case, a third-party library would be used to implement it.

Here are a few third-party libraries that you can use for implementing Lazy loading,

  • React-lazyload

React-lazyload is a library that helps implement Lazy loading in React. Install React-lazy-load using the below command,

npm i react-lazyload

You can wrap the image or whatever element you want to lazy load using the Lazy Load component.

import React, { Suspense, useState } from 'react';

//Importing the library

import LazyLoad from "react-lazyload";

function App() {

 return (

   <div>

     <LazyLoad height={100}>

     <img src={require('./image/elephant.jpg')}/>

       </LazyLoad>

   </div>

 );

}

export default App;

In the code above, you wrap the LazyLoad component on the element you want to lazy load.

The height of the element is set using the height attribute.

When the once property in react-lazyload is used, the element is no longer managed by react-lazyload after the content is displayed.

  • React-Lazy-Load-Image-component:

To install this library file, use the command below,

npm i --save react-lazy-load-image-component

Import the LazyLoadImage and implement Lazy loading by using the below code:

import React, { Suspense, useState } from 'react';

//Importing the library

import { LazyLoadImage } from 'react-lazy-load-image-component';

function App() {

 return (

   <div>

     <h1>Dynamic Import Example</h1>

     <LazyLoadImage src={require('./image/elephant.jpg')} alt="Elephant image"></LazyLoadImage>

   </div>

 );

}

export default App;

The code imports and wraps the LazyLoadImage component from the React Lazy Load Image Component. Other image properties are passed as props.

React Lazy Load Image Component enables you to specify a custom placeholder for components and events for beforeLoad and afterLoad. It is compatible with server-side rendered components and applications and also with TypeScript declarations.

4. Route-based lazy loading

Another way of implementing lazy loading is by using the React Route library. You can get the React route library installed using the command below,

npm install react-router-dom

Now you can implement lazy loading with Route using the below piece of code in the App.js file,

import React, {Suspense,Component} from 'react'

//Importing the required react-router library

import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';

{/* Importing the lazy component and enabling with React.lazy function */}

const LazyComponent = React.lazy(() => import('./LazyComponent'));

class App extends Component {

 render() {

   return (

     <Router>

     <Suspense fallback={<div>Loading...</div>}>

       <Routes>

         <Route path="/" element={<LazyComponent />} />

       </Routes>

     </Suspense>

   </Router>

 );

 }

 }

export default App;

Also, make sure to have the LazyComponent code with the code below,

function LazyComponent() {

   return (

       <div><img src={require('./image/elephant.jpg')}/></div>

   );

 }

  export default LazyComponent;

5. Component-based lazy loading

In component-based lazy loading, the page gets loaded only when the user navigates to the particular component.

For example, on a webpage, if the user is on the homepage, all the other pages will be set to lazy load. These pages will be loaded only when the user clicks or takes any action to view them, or else they won’t be loaded or rendered.

Here’s an example of the same

Consider two components: Home and Image. The code snippet of Home is added below,

function Home() {

   return (

       <h1>Home page is rendered!!!</h1>
    

   );

 }

  export default Home;

Here is the code snippet of the Image,

function Image() {

   return (

       <div><img src={require('./image/elephant.jpg')}/></div>
    

   );

 }

  export default Image;

Note: Ensure to import the required image into the image folder inside the src folder.

Now, you can make the code work from the App.js file,

import React, {Suspense,Component} from 'react'

//Importing the required react-router library

import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';

{/* Importing the lazy component and enabling with React.lazy function */}

const Image = React.lazy(() => import('./Image'));

const Home = React.lazy(() => import('./Home'));

class App extends Component {

 render() {

   return (

     <Router>

       {/* Suspense providing a fallback while the lazy component is loading */}

     <Suspense fallback={<div>Loading...</div>}>

       <Routes>

         {/* Enabling the home page with suspense fallback */}

         <Route path="/" element={<Home/>}/>

         {/* Enabling the image page with suspense fallback */}

         <Route path="/image" element={<Image />} />

       </Routes>

     </Suspense>

   </Router>

 );

 }

 }

export default App;

6. Intersection observer API

Intersection observer is a Javascript API that enables a set of actions to be performed when the element becomes visible to the user scrolling up. With this feature, you can Lazy load the element when the user scrolls to that particular part and unmount it when the user passes over it.

Implement this feature by adding the below code in the App.js file,

import React, { useState, useRef, useEffect, Suspense } from 'react';

// Lazy load the component

const LazyComponent = React.lazy(() => import('./LazyComponent'));

function App() {

 const [isComponentVisible, setComponentVisible] = useState(false);

 const componentRef = useRef(null); // Ref for the element to observe

 // Intersection Observer callback

 const handleIntersection = (entries) => {

   const [entry] = entries;

   if (entry.isIntersecting) {

     setComponentVisible(true); // Set to true when the component is in the viewport

   }

 };

 useEffect(() => {

   // Create a new IntersectionObserver instance

   const observer = new IntersectionObserver(handleIntersection, {

     root: null, // Use the viewport as the root

     threshold: 0.1, // Trigger when 10% of the component is in view

   });

   if (componentRef.current) {

     observer.observe(componentRef.current); // Observe the target element

   }

   return () => {

     // Clean up the observer when the component unmounts

     if (componentRef.current) {

       observer.unobserve(componentRef.current);

     }

   };

 }, []);

 return (

   <div>

     <h1>React Lazy Loading with Intersection Observer</h1>

     {/* Some content to create scroll */}

     <div style={{ height: '100vh', backgroundColor: '#f5f5f5' }}>

       <h2>Scroll down to lazy load the component</h2>

     </div>

     {/* The div where the component is observed */}

     <div ref={componentRef}>

       {isComponentVisible && (

         <Suspense fallback={<div>Loading...</div>}>

           <LazyComponent />

         </Suspense>

       )}

     </div>

    

     {/* More content to scroll */}

     <div style={{ height: '100vh', backgroundColor: '#f5f5f5' }}>

       <h2>This is the end of the view!!</h2>

     </div>

   </div>

 );

}

export default App;

Add the below code in the LazyComponent.js file,

import React from 'react';

function LazyComponent() {

 return (

   <div style={{ padding: '20px', background: '#efefef', border: '1px solid #ddd' }}>

     <h2>This is a lazy load component</h2>

     <p>This will be visible only when you scroll down to this part!</p>

   </div>

 );

}

export default LazyComponent;

As you scroll down to that particular LazyComponent located in the middle, you will notice that it gets loaded because of the implementation of Lazy loading.

With this, you have implemented lazy loading with Intersection Observer API.

7. Dynamic imports

Dynamic imports, a feature in JavaScript that allows you to import modules asynchronously, make lazy loading possible. They improve application performance by loading modules only when they are needed. Reactjs supports dynamic imports.

Below is the syntax for Dynamic import,

import React from 'react';

const MyComponent = React.lazy(() => import('path/to/component'));

This import will not be rendered during compile time but will be rendered only when the promise is resolved.

With Dynamic import, other small components can be loaded easily before the bigger components are imported dynamically.

Here are some simple examples of how you can implement this dynamic import.

In this example, a button will render the image upon clicking it and hide it, and vice versa.

App.js file will have the below code,

import React, { Suspense, useState } from 'react';

// Lazy load the Profile component

const LazyProfile = React.lazy(() => import('./LazyProfile'));

function App() {

 const [showProfile, setShowProfile] = useState(false);

 return (

   <div>

     <h1>Dynamic Import Example</h1>

     <button onClick={() => setShowProfile(!showProfile)}>

       {showProfile ? 'Hide' : 'Show'} Profile

     </button>

     {/* Suspense provides a fallback while the Profile component is being lazy loaded */}

     <Suspense fallback={<div>Loading Profile...</div>}>

       {showProfile && <LazyProfile />}

     </Suspense>

   </div>

 );

}

export default App;

The LazyProfile file will hold the below code,

import React from 'react';

function LazyProfile() {

 return (

   <div>

     <img src={require('./image/elephant.jpg')}/>

   </div>

 );

}

export default LazyProfile;

This will show you a web page that dynamically loads images upon clicking the button, using Lazy loading enabled via dynamic import.

When Should You Not Use Lazy Loading?

Though Lazy loading has many advantages, there are times when you should limit its overuse.

  • Using Lazy load for small applications is not advisable as it may make multiple requests even for small components (resulting in slower performance) instead of loading in a single request.
  • Having too much lazy loading may slow a device with slower processing power, resulting in a poor user experience.
  • Overusing lazy loading can slow the component rendering and affect the user experience. This is because the interaction can make the user wait longer as the component gets rendered via lazy loading.
  • Lazy loading may affect search engine optimization as crawlers won’t be able to understand the application’s content.

How can you Monitor and Measure the Performance Impact of Lazy Loading in a React Application?

Here’s how you can track and evaluate how lazy loading affects a React application’s performance:

  • To gauge user experience and SEO-related performance, use Lighthouse and Core Web Vitals.
  • Use Chrome DevTools and React Profiler to analyze components and keep an eye on network traffic.
  • Monitor Time to Interactive (TTI) and observe how lazy loading impacts bundle size overall with Webpack Bundle Analyzer.
  • Integrate real-time analytics and user monitoring to gain insight into the effects of lazy loading on actual users in a production environment.

Best Practices for Implementing Lazy Loading in React

When applied selectively, lazy loading has the potential to significantly improve performance in React projects.

For best results,

  • Employ preloading for components that are anticipated
  • Prioritize lazy loading for non-critical components
  • Handle errors appropriately and combine them with performance monitoring.

Ensure that user experience and optimization are always balanced and that accessibility and interactivity are not compromised by lazy loading.

Key Benefits of Lazy Loading in React

Here are some key benefits of lazy loading in React:

  • Lazy loading in the react library improves the initial loading time of the webpage as the components are loaded only when needed.
  • Reduced bandwidth consumption as the components are getting loaded only when the user is requesting it.
  • Lazy loading allows for the priority loading of visible content while postponing non-essential elements. This enhances perceived performance by enabling users to engage with key areas of the program without waiting for everything to load.
  • As the application grows, more components will be added, which may affect its performance. With the React Lazy loading feature, you can handle such huge applications by rendering the component only when needed.

Disadvantages and Challenges of Lazy Loading in React

Though there are several advantages to using Lazy loading in React, there are also a few disadvantages.

1. Increase in complexity of code

  • Adding multiple components with Lazy loading can add complexity to the application structure.
  • You may need to handle loading states, error boundaries, and potentially intricate routing.

2. Routing and Navigation issue

  • Lazy loading with React routers can complicate the routing logic as the developers need to handle loading states and introduce nested routes, which add further complications.
  • Also, it can lead to delays when navigating between routes, especially if the component for a new route takes time to load.
  • However, you can identify routing or navigation issues earlier in the testing phase with the help of tools like Browserstack Automate. This tool allows you to run end-to-end testing and cross-browser compatibility tests for React apps using various frameworks & languages.
    For instance, you can use Jest in Browserstack Automate to execute the test cases and find out the navigation or routing issues with the help of this documentation on React App testing with Jest.

Talk to an Expert

3. Handling errors and debugging:

  • A lazy loading component may need to share the state with its parents or sibling components. Then, managing state can become challenging as you may need to pass properties or use context, which complicates the component hierarchy.
  • Also, debugging the issues related to lazy loading can be more complicated as the reasons behind the issues may not be immediately clear, making troubleshooting more challenging.

4. Compatibility and browser support:

  • Lazy loading in React is supported by all modern browsers, but it is not supported by older browsers like Internet Explorer.
  • To overcome this issue, you may need to use Polyfill to make it work in old browsers.

Improved user experience, scalability, and performance optimization are the main advantages of lazy loading in React.

Lazy loading helps you create applications that are highly responsive and efficient while also enhancing page load times, saving bandwidth, and guaranteeing a more seamless user experience across various devices and networks by delaying the loading of non-essential resources.

You can also verify the consistency of user experience on various devices by testing your react code on real devices.

BrowserStack Automate Banner

Testing on real devices will help you understand and debug the application’s behavior under real user conditions.

Test results alter in dev environments and under real user conditions, which is why it is recommended to test on real devices for accurate results.

Leverage BrowserStack’s real device cloud to access over 3500+ real devices, browsers, and OS combinations to deliver a seamless and consistent user experience across different environments.

With the tool, you can run the same tests on multiple device-browser combinations, save time, and ensure maximum test coverage.

Try BrowserStack Automate Now

Tags
Automation Testing Website Testing

Featured Articles

How to Lazy Load Images in Javascript

How to capture Lazy Loading Images for Visual Regression Testing in Puppeteer

Automation Tests on Real Devices & Browsers

Seamlessly Run Automation Tests on 3500+ real Devices & Browsers