Multiple file inputs with one submit button with React Hooks
Tags: react, inputfiles, hooks
Published: 2020-06-13 23:41:47

Recently, I was working on a project and I had to make multiple file inputs. The thing is every input should take only one file with certain type which in my case was _pdf_ , _jpeg_ only. After uploading the file, user should submit all the uploaded files together using only __one__ submit button. In my case, user __doesn't__ have to upload all the files at once. 

The first thing came to my mind is to use `FormData`; however, I had to submit an Array of objects each object should have _file_Id_ and the file itself and let's call it _uploaded_file_ in our example. With `FormData` I couldn't do that, so I had make it in my own way. 

I assume in this example that you are familiar with _Reactjs_ and _hooks_. 

Here are the steps I followed to achieve my goal: 

**1.** Create React component with **3** input files, each input file accepts only _pdf_ , _jpeg_ with unique Id. Also, we want **1** submit button. 

```javascript
import React from 'react';

const MultipleFileInput = () => {
  return (
    <form className="upload--container">
      <div className="upload--button">
        <input id={1} accept=".jpeg, .pdf" type="file" />
      </div>
      <div className="upload--button">
        <input id={2} accept=".jpeg, .pdf" type="file" />
      </div>
      <div className="upload--button">
        <input id={3} accept=".jpeg, .pdf" type="file" />
      </div>
      <button type="submit">Submit</button>
    </form>
  );
};

export default MultipleFileInput;
```
**2.** create state that will hold the Array of objects. 
```javascript
  // state that will hold the Array of objects
  // initialized with empty array
  const [files, setFiles] = useState([]);
```
**3.** Add onChageHandler for each input file. To read these files I have used `FileReader` Read More About [FileReader Web API] (https://developer.mozilla.org/en-US/docs/Web/API/FileReader) 

```javascript
// onChange function that reads files on uploading them
// files read are encoded as Base64
  function onFileUpload(event) {
    event.preventDefault();
    // Get the file Id
    let id = event.target.id;
    // Create an instance of FileReader API
    let file_reader = new FileReader();
    // Get the actual file itself
    let file = event.target.files[0];
    file_reader.onload = () => {
    // After uploading the file
    // appending the file to our state array
    // set the object keys and values accordingly
      setFiles([...files, { file_id: id, uploaded_file: file_reader.result }]);
    };
   // reading the actual uploaded file
    file_reader.readAsDataURL(file);
  }
```
**4.** now let's implement our submit button, for this example we will just console log the results; however, I had to send these files to the server. 
```javascript
  // handle submit button for form
  function handleSubmit(e) {
    e.preventDefault();
    console.log(files)
  }
```
**5.** Finally, Let's add some restrictions to our logic. For example, disable submit button if no file was uploaded. 
```javascript
// button state whether it's disabled or enabled
  const [enabled, setEnabled] = useState(false);
  // using useEffect we can detect if user uploaded any file, 
  // so enable submit button
  useEffect(() => {
    if (files.length === 0) {
      setEnabled(false);
    } else {
      setEnabled(true);
    }
  }, [files]);
// render submit button based on its state. 
{enabled ? (
        <button type="submit">Submit</button>
      ) : (
        <button disabled type="submit">
          Submit
        </button>
 )}
``` 
_**This will be the whole code after all.**_

codesandox [Link] 
(https://codesandbox.io/s/happy-joliot-tqe35?file=/src/App.js)

```javascript

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

const MultipleFileInput = () => {
  // state that will hold the Array of objects
  // initialized with empty array
  const [files, setFiles] = useState([]);
  // onChange function that reads files on uploading them
  // files read are encoded as Base64
  function onFileUpload(event) {
    event.preventDefault();
    // Get the file Id
    let id = event.target.id;
    // Create an instance of FileReader API
    let file_reader = new FileReader();
    // Get the actual file itself
    let file = event.target.files[0];
    file_reader.onload = () => {
      // After uploading the file
      // appending the file to our state array
      // set the object keys and values accordingly
      setFiles([...files, { file_id: id, uploaded_file: file_reader.result }]);
    };
    // reading the actual uploaded file
    file_reader.readAsDataURL(file);
  }
  // handle submit button for form
  function handleSubmit(e) {
    e.preventDefault();
    console.log(files);
  }
  // button state whether it's disabled or enabled
  const [enabled, setEnabled] = useState(false);
  // using useEffect we can detect if user uploaded any file,
  // so enable submit button
  useEffect(() => {
    if (files.length === 0) {
      setEnabled(false);
    } else {
      setEnabled(true);
    }
  }, [files]);

  return (
    <form onSubmit={handleSubmit} className="upload--container">
      <h1> Multiple File Inputs with Signle Submit Button </h1>
      <div className="upload--button">
        <input
          onChange={onFileUpload}
          id={1}
          accept=".jpeg, .pdf"
          type="file"
        />
      </div>
      <div className="upload--button">
        <input
          onChange={onFileUpload}
          id={2}
          accept=".jpeg, .pdf"
          type="file"
        />
      </div>
      <div className="upload--button">
        <input
          onChange={onFileUpload}
          id={3}
          accept=".jpeg, .pdf"
          type="file"
        />
      </div>
      {enabled ? (
        <button type="submit">Submit</button>
      ) : (
        <button disabled type="submit">
          Submit
        </button>
      )}
    </form>
  );
};

export default MultipleFileInput;
``` 

## Final Words, 
I will be glad if someone shared different approach, or any modifications to my current implementation. So, please don't hesitate to share your thoughts.