A Better Way to Render Images in React

Ajay n Jain
2 min readDec 10, 2022

--

Image by Alexandra_Koch from Pixabay

What I used to do

Render an image with img element and if src is null or undefined, render a fallback image.

import { FC } from "react";

type ImageProps = {
src: string;
alt: string;
};

const Image: FC<ImageProps> = ({src, alt}) => {
return <img alt={alt} src={src || "fallback.jpg"}/>;
}

But what if src is malformed or protected that cannot be accessed through the App?
This method fails and renders an empty image with the given alt.

Example of empty image when src is invalid

What happens when an image fails

Whenever an image fails to load, an onError event is triggered, we can use this event to update src to a fallback image.

Updates for the fix

Instead of directly adding an optional condition of the fallback image, we can add an onError event handler to do the same.

useImage Hook

import { SyntheticEvent, useEffect, useState } from "react";
import { ImageProps } from "./Image";

type ImagePropsGetter = () => ImageProps & {
onError: (e: SyntheticEvent<HTMLImageElement>) => void;
};

const useImage = ({
src: srcFromProps,
alt
}: ImageProps): { getImageProps: ImagePropsGetter } => {
const [src, setSrc] = useState(srcFromProps);

const onError = () => {
setSrc("fallback.jpg");
};

useEffect(() => {
setSrc(srcFromProps);
}, [srcFromProps]);

const getImageProps: ImagePropsGetter = () => {
return { src, alt, onError };
};

return { getImageProps };
};

export default useImage;

Image Component

import { FC } from "react";
import useImage from "./useImage";

export type ImageProps = {
src: string;
alt: string;
};

const Image: FC<ImageProps> = (props) => {
const { getImageProps } = useImage(props);

return <img {...getImageProps()} />;
};

export default Image;

No More Empty Images!

Image by Alexandra_Koch from Pixabay

Thanks

--

--

Ajay n Jain
Ajay n Jain

Written by Ajay n Jain

Frontend Engineer! I observe, I write, follow for my deductions. I hope to be a Sherlock in Engineering

No responses yet