Improving web performance is crucial for delivering a smooth user experience. This tip demonstrates how to implement lazy loading for images and videos in React applications using modern best practices. Lazy loading defers non-critical resources until they are needed, reducing initial load times and conserving bandwidth.

Why lazy loading matters

Lazy loading defers the loading of non-critical resources until they are about to enter the viewport. By loading media only when it is needed, you reduce the data transferred during the initial load and improve performance on slow networks. This technique is especially beneficial for media-heavy pages.

Browser support

Native lazy loading is now widely supported across modern browsers. In cases where a browser does not support the native attribute, a JavaScript fallback using the Intersection Observer API can be used:

  • Chrome 77+
  • Firefox 75+
  • Safari 15.4+
  • Edge 79+

Setting up a React application

Start by creating a new React application with Create React App, which ensures you have the latest build configuration:

npx create-react-app@latest my-app
cd my-app
npm start

Implementing lazy loading for images

Native lazy loading

Modern browsers support native lazy loading via the loading attribute. This approach requires no additional JavaScript, simplifying your implementation:

// Above the fold – load immediately
<img
  src="hero.jpg"
  alt="Hero image"
  width="800"
  height="600"
/>

// Below the fold – use native lazy loading
<img
  src="content.jpg"
  loading="lazy"
  alt="Content image"
  width="800"
  height="600"
/>

Advanced lazy loading with intersection observer

For more control in complex scenarios, use the Intersection Observer API via the react-intersection-observer library:

npm install react-intersection-observer@^9.15.1
import { useInView } from 'react-intersection-observer'

function LazyImage({ src, alt, width, height }) {
  const { ref, inView } = useInView({
    triggerOnce: true,
    threshold: 0.1,
  })

  return (
    <div
      ref={ref}
      style={
        {
          width,
          height,
          background: '#f0f0f0'
        }
      }
    >
      {inView ? (
        <img
          src={src}
          alt={alt}
          width={width}
          height={height}
          style={
            {
              width: '100%',
              height: '100%',
              objectFit: 'cover'
            }
          }
        />
      ) : null}
    </div>
  )
}

Implementing lazy loading for videos

Using React suspense

For component-level lazy loading, employ React's built-in Suspense feature to defer the loading of video components:

import React, { Suspense } from 'react'

const VideoPlayer = React.lazy(() => import('./VideoPlayer'))

function App() {
  return (
    <Suspense fallback={<div>Loading video player...</div>}>
      <VideoPlayer />
    </Suspense>
  )
}

Lazy loading video content

Apply lazy loading to the video content itself using the Intersection Observer API:

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

function LazyVideo({ src, poster }) {
  const { ref, inView } = useInView({
    triggerOnce: true,
    threshold: 0.1,
  })

  return (
    <div ref={ref}>
      {inView ? (
        <video
          controls
          preload="none"
          poster={poster}
          style={{ maxWidth: '100%' }}
        >
          <source src={src} type="video/mp4" />
          Your browser does not support the video tag.
        </video>
      ) : (
        <img
          src={poster}
          alt="Video thumbnail"
          style={{ maxWidth: '100%' }}
        />
      )}
    </div>
  )
}

Performance best practices

  • Eager-load content above the fold to ensure a fast initial render.
  • Always provide explicit width and height attributes to prevent layout shifts.
  • Use modern image formats such as WebP with appropriate fallbacks.
  • Implement responsive images using srcset and sizes for different device widths:
<img
  src="image-800w.jpg"
  srcset="
    image-400w.jpg 400w,
    image-800w.jpg 800w,
    image-1200w.jpg 1200w
  "
  sizes="(max-width: 400px) 400px,
         (max-width: 800px) 800px,
         1200px"
  loading="lazy"
  alt="Responsive image"
/>

Optimizing photo delivery with Cloudflare image CDN

In addition to lazy loading, using a Content Delivery Network (CDN) can further boost your application's performance by optimizing how photos are delivered. Cloudflare Image CDN automatically resizes, compresses, and optimizes images, ensuring faster load times and reduced bandwidth consumption—ideal for handling cdn fotos.

Follow these steps to integrate Cloudflare Image CDN into your React application:

  1. Sign up for a Cloudflare account and add your domain.
  2. Enable Cloudflare's Image Resizing feature and configure the desired parameters (such as width and quality).
  3. Update your image URLs to route through Cloudflare. For example:
<img
  src="https://your-domain.com/cdn-cgi/image/width=800,quality=80/yourimage.jpg"
  alt="Optimized image"
  loading="lazy"
  width="800"
  height="600"
/>

This setup leverages the power of Cloudflare Image CDN—one of the best image cdn solutions—to further enhance image optimization and improve load speeds across devices.

Monitoring and debugging

Use Chrome DevTools to monitor lazy loading and diagnose performance issues:

  1. Open the Network tab and filter by "Img" or "Media".
  2. Scroll the page to observe when resources load.
  3. Use the Performance tab to measure impact and check for layout shifts.

Conclusion

Combining lazy loading with CDN-based image optimization significantly improves web performance by deferring non-critical resource loads and delivering media efficiently. For additional media handling and processing, consider using Transloadit's comprehensive services to complement your implementation.