How to display a preview of an image upload in React
Tags: react, javascript
Published: 2023-01-29 08:00:00

## Introduction

In this article, we will explore two different ways to display a preview of an image that has been uploaded in a React application. The first method uses the FileReader API to read the contents of the file and convert it into a data URL, which can then be used as the source for an `<img>` element. The second method uses the `URL.createObjectURL()` method, which creates a URL object that can be used as the src of an img element. Both methods will be demonstrated with code examples and explanations of how to implement them in a React component.

## Displaying image preview using the FileReader API
To display an image that has been uploaded using the HTML `<img>` tag and the File interface, you can use the **FileReader API** to read the file and set the src attribute of the `<img>` tag to the result of the `FileReader.readAsDataURL()` method.

### FileReader API

FileReader is a JavaScript object that allows you to read the contents of a File or Blob object into memory. In this code snippet, it is used to read the contents of the file selected by the user and convert it into a data URL, which can be used as the source for an `<img>` element.

The FileReader object has several methods for reading the contents of a file, such as `readAsText()`, `readAsArrayBuffer()`, `readAsBinaryString()`, and `readAsDataURL()`. In this case, the `readAsDataURL()` method is used to read the contents of the file as a data URL, which is a string representation of the file's data in the form of `"data:<media type>;base64,<data>"`

Once the FileReader object has finished reading the file, it triggers the onloadend event, which calls a callback function that sets the `previewUrl` state variable to the result of the FileReader.

### React Example

In a React component, you can use the `useState` hook to store the file and the `useEffect` hook to read the file when it changes. The `src` attribute of the `<img>` tag can then be set to the result of the `FileReader.readAsDataURL()` method.

```javascript
import React, { useState, useEffect } from 'react';

function ImagePreview() {
  const [file, setFile] = useState(null);
  const [previewUrl, setPreviewUrl] = useState(null);

  useEffect(() => {
    if (!file) {
      return;
    }

    const reader = new FileReader();

    reader.onloadend = () => {
      setPreviewUrl(reader.result);
    }

    reader.readAsDataURL(file);
  }, [file]);

  return (
    <>
      <input type="file" onChange={e => setFile(e.target.files[0])} />
      {previewUrl && <img src={previewUrl} alt="Preview" />}
    </>
  );
}

export default ImagePreview;
```

In this example, when the file input's `onChange` event is triggered, the selected file is set in the component's state using the setFile function. The `useEffect` hook is used to read the file when it changes, by setting the src attribute of the `<img>` tag to the result of the `FileReader.readAsDataURL()` method, which is the data URL of the selected file.

It's also worth noting that you should handle the cases if the user did not select any file or the file is not an image file to prevent any error when trying to read it.

You do not need to use the `useEffect` cleanup function when using the `FileReader()` method because it does not create an object URL like `URL.createObjectURL()` does. Instead, it reads the file and returns the result as a Data URL, which is stored in the previewUrl state. This means that there are no URLs to revoke when the component unmounts or the file changes.

## Displaying image preview using URL.createObjectURL()
You can achieve the same result without using `FileReader()`. One alternative way to do this is by using the `URL.createObjectURL()` method, which creates a URL object that can be used as the src of an img element. Here's an example of how you could modify the code to use this method:

```javascript
function ImagePreview() {
  const [file, setFile] = useState(null);
  const [previewUrl, setPreviewUrl] = useState(null);

  useEffect(() => {
    if (!file) {
      return;
    }

    setPreviewUrl(URL.createObjectURL(file));
  }, [file]);

  return (
    <>
      <input type="file" onChange={e => setFile(e.target.files[0])} />
      {previewUrl && <img src={previewUrl} alt="Preview" />}
    </>
  );
}
```

It's important to note that you should revoke the object URL with `URL.revokeObjectURL(previewUrl)` when the component unmounts or the file changes, otherwise it can cause a memory leak.

```javascript
useEffect(() => {
    if (!file) {
      return;
    }
    setPreviewUrl(URL.createObjectURL(file));
    
    return () => {
      URL.revokeObjectURL(previewUrl);
    }
}, [file]);
```

The `useEffect` hook returns a function that will be called when the component unmounts. Inside this function, we are revoking the object URL, cleaning up memory and avoiding any memory leaks.

## Summary
In summary, this article discussed two ways to display a preview of an image upload in React: using the FileReader API and using the `URL.createObjectURL()` method. The FileReader API allows for reading the contents of a file and converting it into a data URL, which can be used as the source for an `<img>` element. The `URL.createObjectURL()` method creates a URL object that can also be used as the src of an `<img>` element. Both methods allow for the preview of an image before it is uploaded, but it's important to handle cases when a file is not selected or is not an image file, and also to revoke the object URL to avoid memory leaks. Overall, it's up to the developer to decide which method works best for their specific use case.

### ⚡️ Action Points
- [see my blog a about Javascript and React](https://www.nikolasbarwicki.com/)
- give a like or write a comment