Preview File before uploading in React
Tags: react, webdev, javascript, tutorial
Published: 2022-06-04 10:39:57

This article will explain how you can build a file previewer in React that works for images and videos. With this article's help, you can create your own and make support for other files.

> This article only showcases the preview for an image and video.

### Demo

![demo](https://imgur.com/YfD8krA.png)

### Creating `FilePreviewer` Component

First, let's just create a file `components/FilePreviewer.js` after that we need to import two things in that file `useState` and `useRef`.

```jsx
// components/FilePreviewer.js
import { useState, useRef } from "react";
```

Create a `FilePreviewer` function and export it as default.

```jsx
// components/FilePreviewer.js
// ....
export default function FilePreviewer() {}
```

Now we render the UI for FIle Picker and in that there will be two buttons. One for selecting files and the other for clearing file input. Let's see how it's going to look like.
 
```jsx 
// components/FilePreviewer.js

import { useState, useRef } from "react";
export default function FilePreviewer() {
  return (
    <div>
      <h1>Preview Image/Video</h1>
      <div className="btn-container">
        <input type="file" accept="image/*, video/*"  hidden />
        <button className="btn">Choose</button>
        <button className="btn">x</button>
      </div>
      <div className="preview">
        <img src="" alt="" />
        <video controls src=""></video>
      </div>
    </div>
  );
}
```
This is just a starter code, I am going to add more things to this. First, understand what is going on. As you can see inside the `btn-container` class there are three inputs. One for selecting files but I won't use standard file input because when the user selects the file by standard input it shows the name of the file which I don't want (as shown in the following screenshot). 

![filename shows](https://imgur.com/zcMTlet.png)


### Handling File Input button

I have created a new button to choose the file. To make this work we need to create a reference (ref) for file input. and handle the `onChange` event after that it will look something like this.
 
```jsx
// components/FilePreviewer.js

import { useState, useRef } from "react";

export default function FilePreviewer() {
  return (
        // inside .btn-container
        <input ref={filePicekerRef} accept="image/*, video/*"  onChange={previewFile} type="file" hidden />
        // ...
  );
}
```
We will create the `previewFile` function in just a moment to handle the file selection.

#### Creating Custom File input Button

Now as I have hidden the original file input button we need to create our own.

```jsx
// components/FilePreviewer.js

import { useState, useRef } from "react";

export default function FilePreviewer() {
  return (
        // inside .btn-container
        <button className="btn" onClick={()=> filePicekerRef.current.click()} >
			Choose
		</button>
        // ...
  );
}
``` 
In this, I am just triggering the file input button through `ref` when the user clicks this button. 


### File Selection

As we are handling two files (image and video). we need to create two states for that `imagePreview` and `videoPreview`. 

```jsx
// components/FilePreviewer.js

import { useState, useRef } from "react";

export default function FilePreviewer() {

  const [imagePreview, setImagePreview] = useState(null);
  const [videoPreview, setVideoPreview] = useState(null);

  return (
        // ...
  );
}
``` 

Now its' time to create a `filePreview` function. 

```jsx
// components/FilePreviewer.js

export default function FilePreviewer() {
  // ...
  function previewFile(e) {
    // Reading New File (open file Picker Box)
    const reader = new FileReader();

    // Gettting Selected File (user can select multiple but we are choosing only one)
    const selectedFile = e.target.files[0];
    if (selectedFile) {
      reader.readAsDataURL(selectedFile);
    }

    // As the File loaded then set the stage as per the file type
    reader.onload = (readerEvent) => {
      if (selectedFile.type.includes("image")) {
        setImagePreview(readerEvent.target.result);
      } else if (selectedFile.type.includes("video")) {
        setVideoPreview(readerEvent.target.result);
      }
    };
  }
  // ...
}
```
I know it's too much so let's break it down. I am using [FileReader](https://developer.mozilla.org/en-US/docs/Web/API/FileReader) to handle the file selection. 
- I have created an instance called `reader`. 
- Then we are getting the `selectedFile` from an input field (*I am targeting only one file, the user can select multiple files but I am handling only one file*). 
- If the user has selected a file then read that as [Data URLs](https://flaviocopes.com/data-urls).
- When the file is loaded then check for the file type and set the image and video accordingly. 


#### Preview the file 
After file selection is done then we need to preview the file to the user. For that I have already created a container called `.preview`, In that, there were two elements `img` and `video`. Now we need to render these elements conditionally. and after that they will look like this-

```jsx
// components/FilePreviewer.js 

<div className="preview">
	{imagePreview != null && <img src={imagePreview} alt="" />}
	{videoPreview != null && <video controls src={videoPreview}></video>}
</div>
```

#### Clear Input Field 

Now, what if the user wants to clear the input field or remove the image he has selected. We haven't implemented that yet. To do that I've created a `close` button earlier. Now let's just add the functionality to it. When the user clicks on the button then it should fire `clearFiles` function. So let's just create it.


```jsx
// components/FilePreviewer.js 

function clearFiles() {
	setImagePreview(null);
	setVideoPreview(null);
}
```

That's all we need to create a working file Previewer. It can preview an image and a video. 

## Full Code of `FilePreviewer.js`

```jsx
// components/FilePreviewer.js 
import { useState, useRef } from "react";

export default function FilePreviewer() {
  // FIles States
  const [imagePreview, setImagePreview] = useState(null);
  const [videoPreview, setVideoPreview] = useState(null);

  // FIle Picker Ref because we are not useing the standard File picker input
  const filePicekerRef = useRef(null);

  function previewFile(e) {
    // Reading New File (open file Picker Box)
    const reader = new FileReader();

    // Gettting Selected File (user can select multiple but we are choosing only one)
    const selectedFile = e.target.files[0];
    if (selectedFile) {
      reader.readAsDataURL(selectedFile);
    }

    // As the File loaded then set the stage as per the file type
    reader.onload = (readerEvent) => {
      if (selectedFile.type.includes("image")) {
        setImagePreview(readerEvent.target.result);
      } else if (selectedFile.type.includes("video")) {
        setVideoPreview(readerEvent.target.result);
      }
    };
  }

  function clearFiles() {
    setImagePreview(null);
    setVideoPreview(null);
  }

  return (
    <div>
      <h1>Preview Image/Video</h1>

      <div className="btn-container">
        <input
          ref={filePicekerRef}
          accept="image/*, video/*"
          onChange={previewFile}
          type="file"
          hidden
        />
        <button className="btn" onClick={() => filePicekerRef.current.click()}>
          Choose
        </button>
        {(imagePreview || videoPreview) && (
          <button className="btn" onClick={clearFiles}>
            x
          </button>
        )}
      </div>

      <div className="preview">
        {imagePreview != null && <img src={imagePreview} alt="" />}
        {videoPreview != null && <video controls src={videoPreview}></video>}
      </div>
    </div>
  );
}

```


Now we just need to import this container in `App.js` and render it. `App.js` will look something like this.

```jsx
// src/App.js

import "./styles.css";
import FilePreviewer from "./components/FilePreviewer";

export default function App() {
	return (
		<div className="App">
			<FilePreviewer />
		</div>
	);
}
```

You can find the full code in the following Sandbox

{% codesandbox file-previewer-react-z971uj %}

>It takes a little white to render the video if the size of the video is large. You can setup a loading state for that.

## What's Next?
Now after that you can take this further and add support for other files such as text, pdf, and others. You can also add support for multiple files and there are many things you can do.