Implementing 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
Implementing Lazy Loading in React
Home Guide Implementing Lazy Loading in React

Implementing Lazy Loading in React

Lazy loading improves web performance by loading non-essential elements like images, videos, and scripts only when needed.

Overview

What is Lazy Loading in React?

Lazy loading in React delays loading components until needed, reducing initial load time and improving performance. It uses React.lazy() and Suspense for efficient dynamic imports.

Steps to Implement Lazy Loading in React

  1. Import lazy from React and wrap the component to enable lazy loading.
  2. Use <Suspense> with a fallback UI to handle loading states.
  3. Install third-party libraries like react-lazyload or react-lazy-load-image-component for easy lazy loading.
  4. Implement lazy loading with react-router-dom to load components only when routes change.
  5. Load components dynamically when users navigate to them to optimize performance.
  6. Use Intersection Observer API to load elements only when they appear in the viewport.
  7. Implement dynamic imports to asynchronously load modules when needed.

This article covers how lazy loading works in React and provides steps to implement it effectively.

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.

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.

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'));
Copied

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;
Copied

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;
Copied

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
Copied

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;
Copied

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
Copied

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;
Copied

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
Copied

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;
Copied

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;
Copied

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;
Copied

Here is the code snippet of the Image,

function Image() {

   return (

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

   );

 }

  export default Image;
Copied

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;
Copied

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;
Copied

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;
Copied

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'));
Copied

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;
Copied

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;
Copied

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.

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.

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.

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.

BrowserStack Automate Banner

Test Your React Code on Real Devices

Testing your React application on real devices is crucial for understanding and debugging its behavior in real user conditions.

Leveraging BrowserStack Automate enhances test accuracy, optimize performance, and delivers a flawless experience for all users.

Here’s why it matters:

  • Accurate Testing: Development environments may not fully replicate real-world scenarios, leading to discrepancies in test results. Testing on real devices ensures more reliable outcomes.
  • Better Debugging: Identify UI inconsistencies, performance issues, and device-specific bugs that may not appear in simulated environments.
  • Seamless User Experience: Ensure smooth functionality across various devices, browsers, and operating systems for a consistent user experience.
  • Increased Test Coverage: Using BrowserStack’s real device cloud, you can test on 3500+ device-browser-OS combinations, maximizing coverage and compatibility.
  • Time Efficiency: Run tests simultaneously across multiple devices, speeding up debugging and deployment.

Useful Resources for React

Talk to an Expert

Conclusion

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 using platforms like BrowserStack.

Tags
Automation Testing Website Testing