Improve Image loading using Suspense and SWR
This post assumes that you are somewhat familiar with the Suspense API and the SWR library, as it will not cover these two things in much detail.
In case you are not familiar with these two terms, here is a short summary:
- SWR (stale-while-revalidate) is a strategy that first returns data from the cache (stale), then sends a fetch request (revalidate), and finally provides up-to-date data.
<Suspense>component allows you to display a fallback until its children have finished loading.
Let's say we want to create a simple app that displays images of all available Dota 2 heroes:
This is the result:
Not great, right? This will occur on the first load of the app because the images are not cached yet, and we are only displaying a spinner until the data becomes available. Currently, we do not have any logic that listens for image loading. It's time to fix this behavior and use Suspense for image loading as well.
This component may appear overwhelming at first glance, but let's break it down and explain what is happening.
Type definition
First we define a type called Cache which is a record of string keys and values that are either boolean or Promise<void>.
The ImgCache type is then defined as an object with a __cache property of type Cache, and a read method that takes a src parameter of type keyof Cache (a string that is a key in the Cache object) and returns a boolean or Promise<void> value.
The SuspenseImgProps type is then defined as an object with the properties src, alt, height, and key, all of which are required. src is a string representing the source URL of the image, alt is a string representing the alternative text for the image, height is a number representing
the height of the image in pixels, and key is a number representing a unique identifier for the image.
imgCache object
The imgCache object is then defined as an instance of ImgCache.
It has a __cache property initialized as an empty object and a read method that takes a src parameter.
The method first checks if the src key is not present in the __cache object.
If it is not, the method creates a new Promise that resolves with a value of true when the image has finished loading.
The Promise is assigned as the value for the src key in the __cache object.
If the src key is present in the __cache object and its value is a Promise, the method throws the Promise.
If the src key is present in the __cache object and its value is not a Promise, the method returns the value.
SuspenseImg
Finally, the SuspenseImg functional component is defined as an arrow function that takes a single props parameter of type SuspenseImgProps.
It calls the read method of the imgCache object with the src prop as an argument, and then returns an img element with the src, alt, and other props specified in the props object.
Type definition
First we define a type called Cache which is a record of string keys and values that are either boolean or Promise<void>.
The ImgCache type is then defined as an object with a __cache property of type Cache, and a read method that takes a src parameter of type keyof Cache (a string that is a key in the Cache object) and returns a boolean or Promise<void> value.
The SuspenseImgProps type is then defined as an object with the properties src, alt, height, and key, all of which are required. src is a string representing the source URL of the image, alt is a string representing the alternative text for the image, height is a number representing
the height of the image in pixels, and key is a number representing a unique identifier for the image.
imgCache object
The imgCache object is then defined as an instance of ImgCache.
It has a __cache property initialized as an empty object and a read method that takes a src parameter.
The method first checks if the src key is not present in the __cache object.
If it is not, the method creates a new Promise that resolves with a value of true when the image has finished loading.
The Promise is assigned as the value for the src key in the __cache object.
If the src key is present in the __cache object and its value is a Promise, the method throws the Promise.
If the src key is present in the __cache object and its value is not a Promise, the method returns the value.
SuspenseImg
Finally, the SuspenseImg functional component is defined as an arrow function that takes a single props parameter of type SuspenseImgProps.
It calls the read method of the imgCache object with the src prop as an argument, and then returns an img element with the src, alt, and other props specified in the props object.
In the end, we can import the SuspenseImg component and replace the img tag with SuspenseImg. This is the final result:
