Client-side image upload ⬆️ in React
Tags: react, javascript, beginners, tutorial
Published: 2019-12-29 08:13:18

Image upload is one of the important and most used features in your web application. Let's take an example of facebook when you have to update your profile picture, you need to upload an image so that facebook can use it as your profile picture.

Today we will learn to build a simple image uploader which enables the user to select the image and display it in the browser. I hope it will be fun going through the tutorial and getting something out of it 😁. Let's go.

# Setting up the project

For setting up your project, you can use either [create-react-app](https://create-react-app.dev/) or also you can go to [CodeSandBox](http://codesandbox.io).

After creating your project, at first, let's create a simple file input which accepts images for upload

```react
import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
  return (
    <div className="App">
      <input type="file" accept="image/*" multiple = "false" />
    </div>
  );
}

```

Here we are creating a file input that accepts only images and will allow uploading only one file at a time.

Now, let's create a container where the uploaded image will be displayed.

```react
function App() {
  return (
    <div className="App">
      <input type="file" accept="image/*" multiple = "false"/>
      <div
        style={{
          height: "60px",
          width: "60px",
          border: "2px dashed black"
        }}
      >
        <img
          style={{
            width: "100%",
            height: "100%",
            position: "absolute"
          }}
        />
      </div>
    </div>
  );
}
```

Here, we created a container where the image that is uploaded will be shown and also in the future, will be used as the image upload button.
**I wrote the inline styles for tutorial purposes.

Now the fun part let's add an `onChange` handler in the image input and then access the image file in the `handleImageUpload` method.


```react
function App() {
  const handleImageUpload = e => {
    const [file] = e.target.files;
    if (file) {
      console.log(file);
    }
  };

  return (
    <div className="App">
      <input type="file" accept="image/*" onChange={handleImageUpload} multiple = "false" />
      <div
        style={{
          height: "60px",
          width: "60px",
          border: "1px dashed black"
        }}
      >
        <img
          style={{
            width: "100%",
            height: "100%",
            position: "absolute"
          }}
        />
      </div>
    </div>
  );
}
```

We attach an `handleImageUpload` method to the onChange event in the file input we created. In the `handleImageUpload` method we get an `e`(event) object which gives access to the list of files uploaded via the file input we created. We are uploading only one image so we will be accessing the first file from the `FileList` and display the file for now.

Now we will attach a `ref` to the `img` we created where we can display the uploaded image using the `useRef()` hook.

```react
function App() {
  const uploadedImage = React.useRef(null);
  const handleImageUpload = e => {
    const [file] = e.target.files;
    if (file) {
      console.log(file);
    }
  };

  return (
    <div className="App">
      <input type="file" accept="image/*" onChange={handleImageUpload} />
      <div
        style={{
          height: "60px",
          width: "60px",
          border: "1px dashed black"
        }}
      >
        <img
          ref={uploadedImage}
          style={{
            width: "100%",
            height: "100%",
            position: "absolute"
          }}
        />
      </div>
    </div>
  );
}
```

Now we will be using the `FileReader` constructor in order to read the content of the file and will attach the content to the `img` we attached the `ref` to.

```react
function App() {
  const uploadedImage = React.useRef(null);

  const handleImageUpload = e => {
    const [file] = e.target.files;
    if (file) {
      const reader = new FileReader();
      const {current} = uploadedImage;
      current.file = file;
      reader.onload = (e) => {
          current.src = e.target.result;
      }
      reader.readAsDataURL(file);
    }
  };

  return (
    <div className="App">
      <input type="file" accept="image/*" onChange={handleImageUpload} />
      <div
        style={{
          height: "60px",
          width: "60px",
          border: "1px dashed black"
        }}
      >
        <img
          ref={uploadedImage}
          style={{
            width: "100%",
            height: "100%",
            position: "absolute"
          }}
        />
      </div>
    </div>
  );
}
```

In the `handleImageUpload` method we create a `reader` using `FileReader` constructor and then select the `current` from the `uploadedImage` ref which represents the `img` element. We then attach an `onload` event listener to the `reader` we created which when loaded will attach the file url it will read to the `img` element. We then read the file as URL using the `reader.readAsDataURL()` method and pass the `file` selected into it.

So let's see our progress till now

![image uploaded]
(https://media.giphy.com/media/Y1B3KAsHZedrYYt2Nv/giphy.gif)

Now lets remove that ugly input button and use the box created as the image uploader

```react
function App() {
  const uploadedImage = React.useRef(null);
  const imageUploader = React.useRef(null);

  const handleImageUpload = e => {
    const [file] = e.target.files;
    if (file) {
      const reader = new FileReader();
      const { current } = uploadedImage;
      current.file = file;
      reader.onload = e => {
        current.src = e.target.result;
      };
      reader.readAsDataURL(file);
    }
  };

  return (
    <div
      style={{
        display: "flex",
        flexDirection: "column",
        alignItems: "center",
        justifyContent: "center"
      }}
    >
      <input
        type="file"
        accept="image/*"
        onChange={handleImageUpload}
        ref={imageUploader}
        style={{
          display: "none"
        }}
      />
      <div
        style={{
          height: "60px",
          width: "60px",
          border: "1px dashed black"
        }}
        onClick={() => imageUploader.current.click()}
      >
        <img
          ref={uploadedImage}
          style={{
            width: "100%",
            height: "100%",
            position: "absolute"
          }}
        />
      </div>
      Click to upload Image
    </div>
  );
}

```

Here we create a `imageUploader` ref and assign it to the file input, we then hide the ugly file input element using the css `display:none`. After that we will attach an `onClick` listener to the div which clicks the file input when the div is clicked, so that means the image can be uploaded when the div is clicked. We apply some styling to our parent container so that everything appears in the center, now lets see how our output looks like.


![image uploaded]
(https://media.giphy.com/media/JreGr09g71hky3dfht/giphy.gif)


You can find the completed code [here](https://codesandbox.io/s/great-lovelace-6s3i5)

Thankyou.


You can also follow me on [Twitter](https://twitter.com/asimdahall).