Implementing lazy loading for images and videos in React

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
andsizes
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:
- Sign up for a Cloudflare account and add your domain.
- Enable Cloudflare's Image Resizing feature and configure the desired parameters (such as width and quality).
- 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:
- Open the Network tab and filter by "Img" or "Media".
- Scroll the page to observe when resources load.
- 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.