DEV Community

Cover image for Lazy Loading in React & Next.js: Boost Performance the Smart Way
Sachin Maurya
Sachin Maurya

Posted on

Lazy Loading in React & Next.js: Boost Performance the Smart Way

🧠 Introduction:

Ever wondered why your React app takes a hit on performance metrics like LCP or TTI? The culprit is often the sheer volume of code and resources being loaded up front. That's where lazy loading becomes a game-changer. It allows you to defer the loading of components, images, and routes until they’re actually needed β€” speeding up initial load and improving user experience.

In this post, we’ll dive deep into:

  • Component-level lazy loading with React.lazy()
  • Lazy loading routes in Next.js App Router
  • Image optimization using the next/image component
  • Scroll-triggered rendering using IntersectionObserver
  • Best practices for fallback UI like skeleton loaders

βš™οΈ 1. Component-Level Lazy Loading in React

You can lazy load components using React.lazy() combined with Suspense. This defers loading until the component is actually rendered.

import React, { Suspense } from 'react';

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

export default function Home() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <LazySection />
    </Suspense>
  );
}
Enter fullscreen mode Exit fullscreen mode

βœ… Best Practices:

  • Use meaningful fallbacks (like skeleton loaders).
  • Avoid lazy loading above-the-fold components.

🌐 2. Route-Level Lazy Loading in Next.js (App Router)

With Next.js 13+ and the App Router, each route is lazy loaded by default. However, you can still enhance it with loading UI.

Example folder structure:

/app
  /dashboard
    page.tsx
    loading.tsx
Enter fullscreen mode Exit fullscreen mode

When /dashboard is being loaded, loading.tsx is rendered automatically.


πŸ–ΌοΈ 3. Lazy Loading Images

Use the native loading="lazy" attribute for static images or the Next.js Image component for advanced optimization.

import Image from 'next/image';

<Image
  src="/banner.png"
  alt="Banner"
  width={1200}
  height={600}
  placeholder="blur"
  loading="lazy"
/>
Enter fullscreen mode Exit fullscreen mode

πŸ” Why it matters:

  • Reduces initial page size
  • Prevents layout shifts
  • Boosts Core Web Vitals (LCP, CLS)

πŸ‘€ 4. Lazy Rendering with IntersectionObserver

Use this for animations, API calls, or entire sections that should only appear when scrolled into view.

const observer = new IntersectionObserver(callback, options);
observer.observe(targetElement);
Enter fullscreen mode Exit fullscreen mode

Or use libraries like react-intersection-observer for cleaner React integration:

import { useInView } from 'react-intersection-observer';

const { ref, inView } = useInView();

return (
  <div ref={ref}>
    {inView ? <ExpensiveComponent /> : <Skeleton />}
  </div>
);
Enter fullscreen mode Exit fullscreen mode

🧱 5. Skeleton Loaders for Better UX

Using loading placeholders improves perceived performance. You can implement a basic skeleton using TailwindCSS or packages like react-loading-skeleton.

<div className="animate-pulse bg-gray-200 h-6 w-3/4 rounded"></div>
Enter fullscreen mode Exit fullscreen mode

πŸš€ Conclusion

Lazy loading is more than just a performance tweak β€” it's a core optimization strategy. By deferring heavy resources and non-critical components, you not only improve speed but also give your users a better experience.


πŸ”— Coming Next (Part 4):

Error Boundaries & Handling Unexpected Failures Gracefully

Top comments (0)