DEV Community

Cover image for Multiple file inputs with one submit button with React Hooks
Fadi
Fadi

Posted on • Edited on

Multiple file inputs with one submit button with React Hooks

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.

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;
Enter fullscreen mode Exit fullscreen mode

2. create state that will hold the Array of objects.

  // state that will hold the Array of objects
  // initialized with empty array
  const [files, setFiles] = useState([]);
Enter fullscreen mode Exit fullscreen mode

3. Add onChageHandler for each input file. To read these files I have used FileReader Read More About FileReader Web API

// 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);
  }
Enter fullscreen mode Exit fullscreen mode

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.

  // handle submit button for form
  function handleSubmit(e) {
    e.preventDefault();
    console.log(files)
  }
Enter fullscreen mode Exit fullscreen mode

5. Finally, Let's add some restrictions to our logic. For example, disable submit button if no file was uploaded.

// 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>
 )}
Enter fullscreen mode Exit fullscreen mode

This will be the whole code after all.

codesandox Link


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;
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (11)

Collapse
 
mohayman3600 profile image
MohamedAyman3600

Great! I will give it a try in my next project.

Collapse
 
fadiamg profile image
Fadi

Cool!
Let me know if you needed any help my friend.

Collapse
 
briansamu profile image
Brian Samu

Thank you so much!!! I couldn't find a solution anywhere and I was about to give up. Much appreciated.

Collapse
 
viniciusrio profile image
Vinicius Rio

Hey dude, thanks for that. I started learn react this month and I understand you code and your article. Great!

Collapse
 
fadiamg profile image
Fadi

Heyy buddy, I'm glad that liked my article.
Let me know if you needed any help ! :)
Happy Coding !

Collapse
 
ehab_elkady_ profile image
EHAB EL-KADY

That's great!!
That must have taken you a lot of search

Collapse
 
fadiamg profile image
Fadi • Edited

Yeah it did, but it was worth it.
Thank you <3

Collapse
 
dreaprince profile image
odusoga holalekan

Wow, this is great. This really helps, PLS can you adjust this code for just one input type file instead of multiple

Collapse
 
dienamo profile image
dienamo

Thank Fadi, great tutorial

Collapse
 
tdeovrat profile image
Deovrat Tiwari

How do i add a button to add more files after uploading one file?

Collapse
 
tr1010 profile image
H N

Thank you so much. You made my day.