React Progressive Graceful Image with Lazy-Loading — All-in-one ReactJS npm package for Image Loading
- npm i react-progressive-graceful-image
- Supports features like Custom Image Placeholder/Loader Component, srcset, lazy Loading, Graceful Loading, Progressive Image Loading.
- Use of Intersection Observer and navigator.onLine (Better performance and Optimization)
I was working on an e-commerce PWA and you know what is there on an e-commerce platform? Images, more images and well, a lot more images. The truth is, with the increase in internet speed, images are everywhere now, be it e-commerce/social media/blog/news/dating or any other site.
So what’s the big deal in loading images? Just make an <img src=path-to-image /> tag and done!! I am sure you are thinking it’s not even that easy. The problem is loading of an image takes time. Particularly, when there is a huge number of high-quality images on a single page.
To give a better user experience, various things can be done:
- Image Placeholder — Keep a static image(png/svg) / a loader(gif) / a colored background div(usually grey) / a grey div with shimmer effect like the one below, until the real image is downloaded.
- Progressive JPEG — Use Progressive JPEG instead of a normal Baseline JPEG image, although it’s not much in the control of client-side code. Here is an example.
- Lazy Loading — Don’t load an image until it is visible or close to the viewport. Below gif explains it.
- Graceful Loading — Display the placeholder until the image is fully loaded and retry image loading even if network error happens(mostly when a device switches network for some reason like power/network failure).
- Progressive Image Loading — Sites like medium, facebook, etc uses a tiny version of the real image with blur filter until the real image is downloaded and then uses some CSS transition to replace the tiny one. Here is an example.
- srcset attribute —used to let the browser automatically choose image based on device screen size and/or device pixel ratio(DPR).
Huh? That’s a lot of information and so many things can be done. Now to build an <Image/> component in ReactJS with one or two of the above features is easy, but how about building an <Image/> component with all of the above features?
Drumroll, please!! Enter the savior, the superhero npm package…
- Why do we need various combinations together, why not implement just one variation, for example - Progressive Image Loading?
— Let’s take an example. Home Page of an e-commerce has various sections, some with ads for which tiny images might be available. Since it’s a landing page that gets maximum eyeballs of visitors, hence better user experience is required. But “Search result page” or “Product description page” may serve images for which tiny images are not available(why you ask? One of the reasons, it’s costly). So we need let’s say, a grey div placeholder with shimmer effect. And as a developer, you don’t want to make multiple components for images. Similarly, there can be other use-cases. You get my point.
- Why do we use this npm package? Is there any other better package?
— I found some really good packages like react-shimmer, react-graceful-image, and react-progressive-image but honestly speaking, most of them lacked one or more important features. Like, react-graceful-image lacked shimmer effect and react-progressive-image lacked lazy-loading and graceful-loading. In fact, I started by forking react-progressive-image and adding new features from react-graceful-image. Later, I improved upon them.
- What about performance, optimization, and browser support?
— Currently, the package size is 3.6kb. I have used Intersection Observer for Lazy Loading (Better Performance) as compared to throttling scroll event listeners which run on the main thread. One big reason, Intersection Observer runs on a separate thread in the Browser. Read more about it here and see it in action at @researchgate/react-intersection-observer which is the only dependency of this package.
Also, the retry strategy for graceful loading in react-graceful-image was not quite optimized. It would also hang the screen sometimes when the device goes offline and a lot of image requests are sent simultaneously which would fail anyway. So I have used navigator.onLine based strategy for optimization.
In case Intersection Observer is not supported by a browser, its polyfill is available here.
Great!! How do I use it? Any demo?
Here you go…
react-progressive-graceful-image-simple-example - CodeSandbox
CodeSandbox is an online editor tailored for web applications.
You can find more examples and documentation on npm or github.
In case you find any issues or improvements, PRs and contributions are welcome on github.
Extra Browny Stuff: Always use padding-percentage solution to wrap your custom <Image/> component to prevent any reflow and improve browser performance as explained in this article. Here is a small code snippet to make the best use of this logic with this npm package.
Thank you for reading this article. Please share and clap if you liked it.
Let me know in the comments below if you want me to give more details about the code implementation of this npm package, as some have asked me personally.