[Nextjs Tip] How to resize image URL dynamically with next/image component
In Next.js, To use the <image /> component, width and height(props) are required and the value should be integer in pixels unless layout(props) is ‘fill’
Let’s say you want to render images via image URL from a server. There is a big chance that you might not know the size of the images. Let’s have a look at what we can do in this case.
# Case 1
Next.js recommends getting image dimensions along with the URL from a server.
If your application is retrieving image URLs using an API call (such as to a CMS), you may be able to modify the API call to return the image dimensions along with the URL.
What If you’re in a position where you are unable to get dimensions from the server? You have to get the dimensions on your client-side.
To get dimensions, Refer to the code below. You can get image dimensions from the image URL.
// image.jsexport const getImageRef = (url) => { return new Promise((resolve, reject) => { const img = new Image(); img.onload = () => resolve(img); img.onerror = () => reject(); img.src = url; });};// Usageconst setImageSize = async () => { const img = await getImageRef(src); return { width: img?.width || 0, height: img?.height || 0 };};
# Case 2
What if you want to scale the image to fit the width of the container and auto-size the height along with the width. (width=’100%’; height=’auto’) You can use the getImageRef function from Case 1 and layout=’responsive’. For this case, I created a new component, <CustomImage />.
// CustomImage.tsimport { useEffect, useState } from 'react';import Image from 'next/image';import getImageRef from './image.ts';function CustomImage({ className, layout, src, ...props }) { const [imgSize, setImgSize] = useState({ width: 0, height: 0 }); useEffect(() => { const setImageSize = async () => { const img = await getImageRef(src); setImgSize({ width: img?.width || 0, height: img?.height ||
0 }); }; setImageSize(); }, []); return ( <div className={className}> <Image {...props} src={src} width={imgSize.width} height={imgSize.height} layout={layout} /> </div> );}CustomImage.defaultProps = { className: '', layout: 'responsive',};
// Usage<CustomImage src={randomImageUrl} alt='random alt'/>
When you insert the image URL into the <CustomImage />, it will get the original size of the image which means it will have the image dimensions. then, the layout=’responsive’ will scale the image to fit the width of the container.
Conclusion
I believe there are more ways to handle these cases. Please feel free to share your ways or better ways!