DEV Community

Jaimin Patel
Jaimin Patel

Posted on AI-assisted

How I Made My React Website Load Faster by Fixing Images

Top of post

The easiest performance win in React isn't always your JavaScript. Sometimes it's your images.

I used to think performance optimization meant splitting bundles, memoizing components, and chasing Lighthouse scores.

Then I opened Chrome DevTools on one of my own React projects.

The result? Images were quietly eating most of the page weight — way more than my JS bundle, my fonts, everything else combined.

A hero banner that looked perfect on my laptop was making mobile users download a multi-megabyte file just to see a heading.

That's when it clicked: image optimization isn't a nice-to-have. It's one of the fastest ways to make a React site actually feel faster.

Here's exactly what I changed.

Why Image Optimization Matters

Every extra second of load time costs you something — a visitor who bounces, a search ranking that slips, a bandwidth bill that keeps climbing.

Why Image Optimization Matters

None of that is dramatic on its own. But it adds up fast, and images are usually where it's hiding.

First Rule: Stop Uploading Giant Images

We've all done it.

Designer sends a beautiful 4000×3000 image.

We drop it into React.

Then display it inside a 400px card.

The browser still downloads the full file — every pixel of it, whether you show it or not.

Instead, match your image size to where it's actually displayed:

Device Image Width
Mobile 400px
Tablet 800px
Desktop 1200px

Your users won't notice the difference in quality. They'll definitely notice the faster loading.

The Two Formats I Use for Almost Every Project

The Two Formats I Use for Almost Every Project

WebP — if you're still serving JPEGs everywhere, you're leaving free performance on the table. WebP usually keeps the same visual quality while shrinking the file size significantly.

Example:

JPEG → 500KB
WebP → around 320KB

That's hundreds of kilobytes saved without changing your design at all.

AVIF — takes compression even further. I've seen hero images drop from 500KB to nearly 200KB with almost no visible quality loss. Browser support is good enough now that it's worth using wherever you can.

Lazy Loading Is Basically Free Performance

One thing I always ask myself now: "Does this image need to load immediately?"

Usually the answer is no.

Lazy Loading Is Basically Free Performance

Gallery images. Blog thumbnails. Testimonials. Footer logos. All of these can wait until users actually scroll near them.

React makes it ridiculously simple:

<img
  src="/gallery/photo.webp"
  alt="Gallery"
  loading="lazy"
/>
Enter fullscreen mode Exit fullscreen mode

One attribute. Less network traffic. Faster initial load.

But Don't Lazy Load Everything

Your hero image is different. If it's the biggest thing users see first, load it immediately — not lazily.

The Hero Image Can Make or Break Your LCP

Google's Largest Contentful Paint (LCP) is often just your hero image, plain and simple.

The Hero Image Can Make or Break Your LCP

If it's delayed, your performance score suffers. Instead of this:

<img src="/hero.webp" loading="lazy" />

Enter fullscreen mode Exit fullscreen mode

Use this:

<img
  src="/hero.webp"
  loading="eager"
  fetchPriority="high"
  alt="Hero"
/>
Enter fullscreen mode Exit fullscreen mode

Small change. But now the browser knows this image deserves priority over everything else on the page.

The Page Jump Problem (CLS)

Have you ever tried clicking something and the page suddenly moved because an image loaded underneath your cursor?

That's Cumulative Layout Shift. The browser didn't know how much space to reserve, so it grabbed space the moment the image arrived — shoving everything else out of the way.

Bad:

<img src="/product.jpg" alt="Product" />
Enter fullscreen mode Exit fullscreen mode

Better:

<img
  src="/product.jpg"
  alt="Product"
  width={600}
  height={400}
/>
Enter fullscreen mode Exit fullscreen mode

Or use CSS:

.product-image {
  aspect-ratio: 3 / 2;
}
Enter fullscreen mode Exit fullscreen mode

Now the layout stays stable while the image loads, no matter how slow the connection is.

Mobile Users Don't Need Desktop Images

This is probably the biggest missed opportunity I see in React codebases.

Mobile Users Don't Need Desktop Images

Why send a 1200px image to someone on a 390px phone? That's exactly why srcSet exists:

<img
  src="/image-800.webp"
  srcSet="
    /image-400.webp 400w,
    /image-800.webp 800w,
    /image-1200.webp 1200w
  "
  sizes="(max-width: 768px) 100vw, 800px"
  alt="Responsive"
/>
Enter fullscreen mode Exit fullscreen mode

The browser automatically picks the right version. No complicated logic. No JavaScript required.

The Image Component I Kept Rebuilding

After repeating these optimizations across multiple projects, I noticed I was writing the same image component again and again. Every project needed:

Lazy loading
Blur placeholders
Skeleton loaders
WebP support
AVIF support
Priority loading for hero images
Aspect ratio to prevent CLS

So I turned it into a reusable package.

React Smart Image

Instead of wiring everything manually, I can now just write:

import { SmartImage } from "@concatstring/react-smart-image";

<SmartImage
  src="/hero.webp"
  alt="Hero"
  width={1200}
  height={700}
  priority
  aspectRatio="12:7"
/>
Enter fullscreen mode Exit fullscreen mode

It handles most of these best practices automatically — which saves real time, especially on bigger React projects with hundreds of images scattered across pages.

My Go-To Image Optimization Checklist

Before shipping any React page, I run through this quickly:

Resize images before uploading
Use WebP or AVIF whenever possible
Lazy load below-the-fold images
Prioritize the hero image
Set width and height (or aspect ratio)
Use srcSet for responsive images

Five minutes on this list usually saves users several seconds of loading time. Honestly, it's one of the highest-ROI optimizations I've found in React — full stop.

Try React Smart Image

If you don't want to configure every image manually, check out the package I built.

React Smart Image — lazy loading, blur placeholders, skeleton loaders, WebP & AVIF support, LCP priority loading, responsive images, and CLS prevention, all in one component.

NPM Package: https://www.npmjs.com/package/@concatstring/react-smart-image
GitHub: https://github.com/concatstring-account/react-smart-image
Live Demo: https://react-smart-image.netlify.app/
Product Page: https://labs.concatstring.com/products/react-smart-image

If you're building React apps regularly, these small image optimizations add up — and your users (and your Lighthouse score) will thank you for it.

Top comments (0)