Skip to content

Edvins Antonovs

Creating a custom React Hook to fetch image dimensions

In this post, I'll show you how to create a custom React hook to fetch the dimensions of an image from a URL. This can be particularly useful when you need to know the image size before rendering it, for layout calculations, or to handle responsive images effectively. I've built this hook for a my side project, but you can adapt it to suit your needs.

The hook itself

First, let's create our custom hook useImageDimensions. This hook will take an image URL as input, load the image, and return its dimensions, loading state, and any potential error.

useImageDimensions.js
1import { useState, useEffect } from 'react';
2
3const useImageDimensions = (src) => {
4 const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
5 const [isLoading, setIsLoading] = useState(true);
6 const [error, setError] = useState(null);
7
8 useEffect(() => {
9 setIsLoading(true);
10 setError(null);
11
12 const img = new Image();
13 img.src = src;
14 img.onload = () => {
15 setIsLoading(false);
16 setDimensions({ width: img.naturalWidth, height: img.naturalHeight });
17 };
18 img.onerror = (error) => {
19 setIsLoading(false);
20 setError(error);
21 };
22 }, [src]);
23
24 return { dimensions, isLoading, error };
25};
26
27export default useImageDimensions;

So what happens here? Let's break it down:

  1. We initialise three state variables: dimensions, isLoading, and error.
  2. We use the useEffect hook to handle side effects. Every time the src changes, the effect runs:
    • Set isLoading to true and clear any previous error.
    • Create a new Image instance, set its src to the provided URL, and define onload and onerror handlers.
    • When the image loads successfully, update the dimensions state.
    • If an error occurs, update the error state.

How to use the hook

Next, let's create a React component that uses our custom hook.

ImageComponent.jsx
1import React from 'react';
2import useImageDimensions from './useImageDimensions';
3
4const ImageComponent = ({ src }) => {
5 const { dimensions, isLoading, error } = useImageDimensions(src);
6
7 if (isLoading) {
8 return <div>Loading...</div>;
9 }
10
11 if (error) {
12 return <div>Error: {error.message}</div>;
13 }
14
15 return (
16 <div>
17 Image Width: {dimensions.width}, Image Height: {dimensions.height}
18 </div>
19 );
20};
21
22export default ImageComponent;

Here's what's happening in this component:

  1. We call useImageDimensions with the src prop to get the image dimensions, loading state, and error.
  2. Conditional Rendering:
    • While loading, display a loading message.
    • If an error occurs, display the error message.
    • Once loaded successfully, display the image dimensions.

Using a custom hook like useImageDimensions can simplify your code and make it reusable across different components. It encapsulates the logic for loading an image and getting its dimensions, allowing you to focus on the component's rendering logic.

Feel free to adapt and expand this hook to fit your specific needs. You could add more features like caching, error handling, or custom options for image loading. I hope you found this post helpful.

© 2024 by Edvins Antonovs. All rights reserved.