ReviseAlgo Logo

Performance

Lazy Loading

Master React lazy loading, covering React.lazy components, dynamic imports, viewport-triggered loading, and initial bundle optimizations.

Last Updated: July 15, 2026 12 min read

1. Learning Objectives

In this lesson, you will learn how to optimize page load speeds by loading code on demand. By the end of this topic, you will be able to:

  • Differentiate eager loading from lazy loading.
  • Import components dynamically using the React.lazy API.
  • Configure dynamic imports using the import() function.
  • Defer rendering of off-screen components using viewport triggers (Intersection Observer).
  • Reduce initial application bundle sizes to improve load performance.

2. Overview

By default, when a user visits a React website, the browser downloads the entire application bundle before rendering anything. **Lazy Loading** is an optimization technique that splits this bundle into smaller chunks, downloading and rendering specific components (like heavy admin panels or modals) only when they are needed.

3. Why This Topic Matters

Lazy loading is key to building fast, high-performance web applications:

  • Faster Time to Interactive (TTI): Reducing the size of the initial JavaScript bundle allows the browser to download, parse, and render the page much faster.
  • Bandwidth Savings: Users only download the code for the sections of the site they actually visit, saving mobile data.

4. Real-World Analogy

Think of lazy loading like **a chef assembling ingredients for a meal**:

  • Eager Loading: Chopping and preparing every single ingredient in the pantry (pizza dough, pasta, steak, soup, dessert) before the customer even orders. This wastes space and delays service.
  • Lazy Loading: Preparing only the pizza dough initially. When the customer orders dessert (requests the component), you get the dessert ingredients out of the freezer and assemble it. You only prepare ingredients when they are ordered, saving kitchen resources.

5. Core Concepts

Below is a comparison of Eager and Lazy loading patterns:

Property Eager Loading Pattern (Default) Lazy Loading Pattern (Optimized)
Initial Download Size High. Downloads the entire site's code at once. Low. Downloads only the code needed for the landing page.
Page Transitions Instant (since the code is already loaded). Requires a brief loading pause as new chunks download.
Implementation Standard static import statements (e.g. import X from 'x'). Dynamic imports paired with React.lazy and Suspense.

6. Syntax & API Reference

This example shows how to configure a component for lazy loading using `React.lazy`:

7. Visual Diagram

This diagram displays how bundlers split files and download them dynamically in the browser:

8. Live Example — Full Working Code

Below is a complete HTML page demonstrating lazy loading using a simulated dynamic import:

What just happened? Clicking "Load Heavy Component" triggers the rendering of LazyHeavyComponent. Because it is wrapped in `lazy` and `Suspense`, React displays the "Downloading javascript chunk..." fallback UI while downloading the code in the background. Once the promise resolves, it renders the loaded component.

9. Interactive Playground

Try It Yourself Challenges:

  1. Change the timeout delay in delayImport to 3 seconds to test how the fallback loading indicator behaves on slow networks.
  2. Add an "Unmount" button to reset the state, and verify how the component behaves when loaded a second time (hint: the chunk is already cached by the browser).

10. Common Mistakes

Mistake Why it happens Wrong Correct
Omitting the Suspense wrapper for lazy components If you render a lazy component without wrapping it in a <Suspense> element, React will crash and throw a rendering error when the component attempts to mount. <LazyWidget /> (missing Suspense parent) <Suspense fallback=<Spinner />>
<LazyWidget />
</Suspense>
Importing lazy components inside render loops or components Calling React.lazy inside a component block redeclares the lazy import on every render cycle. This loses the cached bundle and causes the component to reset on every parent render. function App() {
const LazyWidget = lazy(() => import('./Widget'));
}
Always declare React.lazy imports outside of component blocks, near the top of the file.

11. Best Practices

  • Declare lazy imports globally: Always call React.lazy outside of component rendering blocks.
  • Use default exports: Components imported using React.lazy must be exported as **default exports**.
  • Optimize loading states: Choose lightweight components or skeleton frames for your `Suspense` fallbacks to keep the loading experience smooth.
  • Integrate with Routing: Use lazy loading on route components (like `/admin` or `/dashboard`) to split code naturally.

12. Browser Compatibility/Requirements

`React.lazy` and dynamic imports require browsers that support ES modules (supported in all modern browsers).

13. Interview Questions

Q1: How do you implement lazy loading for components in React? Discuss the roles of `React.lazy` and ``.

Answer: To implement lazy loading: (1) declare the component using `React.lazy` and a dynamic import statement (e.g. `const Lazy = lazy(() => import('./Comp'))`). (2) Wrap the lazy component in a `` wrapper when rendering. The `` component handles the pending state by rendering the `fallback` UI while the javascript bundle downloads, swapping in the actual component once the download completes.

Q2: Why must `React.lazy` components be exported as default exports? How can you lazy load named exports?

Answer: `React.lazy` expects a promise that resolves to a module object with a `.default` property containing the React component. To lazy load a named export, you must resolve the promise with an object containing the named export mapped to the default key: `lazy(() => import('./Module').then(module => ({ default: module.NamedExport })))`

14. Debugging Exercise

Identify why this router lazy-loading setup crashes the browser when visiting '/admin':

View Solution

Diagnosis: The lazy-loaded AdminPanel component is not wrapped in a Suspense component. When React matches the route and tries to mount the lazy component, it crashes because there is no fallback loading UI declared.

Fix: Wrap the lazy component or the entire routing tree in a Suspense wrapper:

15. Practice Exercises

Exercise 1: Viewport lazy-loaded card details

Build a component named LazyCard. Using a scroll box or the Intersection Observer API, trigger the dynamic loading of a heavy details sub-component only when the card intersects with the user's viewport.

16. Scenario-Based Challenge

The Multi-Tenant Core Admin Panel Bundler Splitting:

You are designing a SaaS platform where different companies use different widgets. The main page bundle is getting too large. Explain how you would structure the dashboard using React.lazy and dynamic imports to ensure users only download the code for the widgets enabled for their specific company.

17. Quick Quiz

Q1: Which method is called to dynamically import a JavaScript module in modern JS?

A) require()

B) import()

C) fetchModule()

Answer: B — The dynamic import() function returns a promise that resolves to the module namespace object, allowing on-demand code loading.

18. Summary & Key Takeaways

  • Lazy loading splits your code bundle to improve the page load performance.
  • Import components dynamically using the React.lazy() API.
  • Always wrap lazy components in a Suspense component with a fallback UI.
  • Declare React.lazy imports outside of component blocks.
  • Lazy loaded components must be exported as default exports.

19. Cheat Sheet

Lazy API Syntax Description
const LC = lazy(() => import('./C')); Imports a component dynamically for lazy loading (requires default export).
<Suspense fallback={<Loader />}> Wraps lazy components and displays a fallback UI during download.
() => import('./M').then(m => ({ default: m.N })) Helper syntax to lazy load a named export.
---