DEV Community

Cover image for Fixing lazyload images with React Server-Side Render
Hieu Nguyen
Hieu Nguyen

Posted on β€’ Edited on

1 1

Fixing lazyload images with React Server-Side Render

I've recently realized my server render pages has a problem. The offscreen lazyload image don't show up.

In case you don't know, offscreen images won't load until it shows up onscreen. It helps to reduce unecessery loading to improve performance.

As usual, I impletemented image lazy loading by (1) get all img elements, (2) move photo URL to data-src, and remove src. Then (3) observe whenever each of them scrolled onscreen, move the photo URL back to src to load.

It works when React running on the client-side. But when render on the server-side, the images don't show up.

Turn out, it's a little different. As usual, the server will return a hydrated React page. Then the client will re-render the page again as a normal React page.

The problem was, the lazyload function executed twice as well. The first time, src is a link, and set to empty after assigning the link to data-src. Then the second time, src was empty, and that empty value is again, assigned to data-src. And when users viewing the page, it will start to load an empty value.

I fixed this problem by checking if src is not empty, before moving it to data-src.

In case you're looking for the code, here is a basic lazyImages.ts with some favors (add loading class, check for offscreen images)

var intersectionObserver: IntersectionObserver;
function run(entry: IntersectionObserverEntry) {
if (entry.isIntersecting) {
let target = entry.target as HTMLImageElement;
target.src = target.dataset.src as string;
target.classList.remove("loading");
intersectionObserver.unobserve(target);
}
}
function lazyImages(opts?: { rootMargin: string }) {
let _opts = Object.assign({ rootMargin: '18%' }, opts);
intersectionObserver = new IntersectionObserver(function (entries) {
entries.forEach(run)
}, _opts);
Array.from(document.querySelectorAll("img")).forEach(element => {
if (!element.dataset.src) {
let bound = element.getBoundingClientRect();
element.classList.add("loading");
// apply lazy load for images under to fold
if (bound.top > window.innerHeight) {
element.dataset.src = element.getAttribute("src") as string;
element.removeAttribute("src");
intersectionObserver.observe(element);
} else {
element.onload = function() {
element.classList.remove("loading")
}
}
}
})
}
view raw lazyImages.ts hosted with ❀ by GitHub

You can use the lazyImages as following:

lazyImages();

// offset before the image is scrolled into view
lazyImages({ rootMargin: "100px" });
Enter fullscreen mode Exit fullscreen mode

Posted on Fixing lazyload images with React Server-Side Render

Do your career a big favor. Join DEV. (The website you're on right now)

It takes one minute, it's free, and is worth it for your career.

Get started

Community matters

Top comments (2)

Collapse
 
dalbir profile image
Dalvir β€’ β€’ Edited

How I can use this in My React Application, example please. And also please correct the type in lazyImages

Collapse
 
hieussr profile image
Hieu Nguyen β€’

To use the function, you will need to call lazyImages as following:

lazyImages();

// offset before the image is scrolled into view
lazyImages({ rootMargin: "100px" });
Enter fullscreen mode Exit fullscreen mode

Thanks for mentioning, I've added this to the post.

Besides, what type was incorrect?

Image of AssemblyAI

Automatic Speech Recognition with AssemblyAI

Experience near-human accuracy, low-latency performance, and advanced Speech AI capabilities with AssemblyAI's Speech-to-Text API. Sign up today and get $50 in API credit. No credit card required.

Try the API

πŸ‘‹ Kindness is contagious

Dive into an ocean of knowledge with this thought-provoking post, revered deeply within the supportive DEV Community. Developers of all levels are welcome to join and enhance our collective intelligence.

Saying a simple "thank you" can brighten someone's day. Share your gratitude in the comments below!

On DEV, sharing ideas eases our path and fortifies our community connections. Found this helpful? Sending a quick thanks to the author can be profoundly valued.

Okay