DEV Community

Cover image for Uploading Files with React (POST Request)
Luqman Shaban
Luqman Shaban

Posted on

Uploading Files with React (POST Request)

Introduction

React applications are known for their interactivity and user-friendliness. But what if you want users to upload files, like images or document? Don't worry! In this article I'll guide you through the process of creating a React component that will handle file uploads. We'll break down the process, explore using libraries like axios, and even touch upon handling upload progress and displaying success/error messages.

Project Set Up
To get started, I've used vite to create the react app and picked typescript. Follow the guide on how to set up react using vite. After you're done setting up the project, open it in a code editor of your choice. (I'll be using VsCode). For styling, we'll be using tailwind css, here's a guide on how to set it up. Once done, Open App.tsx and replace it's content with the following:

export default function App() {
  return (
    <h1 className="text-3xl font-bold underline">
      Hello world!
    </h1>
  )
}
Enter fullscreen mode Exit fullscreen mode

open your terminal and run:
npm run dev

you should see something similar to this

Image description

Open the port on your browser and you should see

Image description

Creating the HTML Form
*Step 1 *- Delete the h1 element and replace it with a form. To make things easier, I have already styled the form for you.

export default function App() {
  return (
    <div className="flex justify-center items-center pt-44">
      <form>
        <div className='flex flex-col gap-y-4'>
          <div className="flex items-center justify-center w-full mt-5">
            <label htmlFor="dropzone-file" className="flex flex-col items-center justify-center p-3 w-full h-36 border-2 border-gray-300 border-dashed rounded-lg cursor-pointer bg-[#ffffff] hover:bg-[#f9f9f9]">
              <div className="flex flex-col items-center justify-center pt-5 pb-6">
                <svg className="w-8 h-8 mb-4 text-[#7b7b7b] dark:text-[#9b9b9b]" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 16">
                  <path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M13 13h3a3 3 0 0 0 0-6h-.025A5.56 5.56 0 0 0 16 6.5 5.5 5.5 0 0 0 5.207 5.021C5.137 5.017 5.071 5 5 5a4 4 0 0 0 0 8h2.167M10 15V6m0 0L8 8m2-2 2 2" />
                </svg>
                <p className="mb-2 text-sm text-[#7b7b7b] dark:text-[#9b9b9b]"><span className="font-semibold">Click to upload</span> or drag and drop</p>
                <p className="text-xs text-[#7b7b7b] dark:text-[#9b9b9b]">pdf, docx, doc (MAX.14MB)</p>
              </div>
              <input id="dropzone-file" type="file" className="hidden" accept='.pdf, .docx, .doc, .odt' required />
            </label>
          </div>

          <button className="py-3 w-full bg-[blue] text-white rounded-lg text-center">Submit</button>
        </div>
      </form>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

The style is very minimal but it serves the purpose for now. However, you may modify the style to match your own preferences.

Adding Functionality
Up to this point you might have noticed that no message is shown after the file has uploaded. To address this challenge, we'l use React's useState hook to dynamically display a message letting the user know that the file has being successfully uploaded.

Step 1 - import useState from React.
import { useState } from "react"

*Step 2 *- Create a state variable
const [isFileUploaded, setIsFileUploaded] = useState(false)

Step 3 - conditionally render the message after file u

pload
 {/* Notify the user after successful file upload */}
          {isFileUploaded && <div className="flex flex-col gap-y-1 w-full">
            <p className="text-center text-blue-800 text-sm">File uploaded</p>
            <div className="h-1.5 w-full bg-green-500 rounded-full"></div>
          </div>}
Enter fullscreen mode Exit fullscreen mode

Storing the file in a state variable
To save the upload file, we'll create a state variable and method to listen for file uploads.

  • Create the state variable const [file, setFile] = useState<File | null>(null)

In the above code we declaring a state variable and assigning File or null type.

  • Create HTML event method that listens for file uploads
const handleFileInput = (e: React.ChangeEvent<HTMLInputElement>) => {
    const files = e.currentTarget.files
    if(files)
    setFile(files[0])
    // show success message on file upload
    setIsFileUploaded(true)
  } 
Enter fullscreen mode Exit fullscreen mode

This code snippet handles what happens when a user selects a file for upload.

  • handleFileInput is the function triggered when the user interacts with the file input element. It receives an event object (e) containing details about the change.
  • Inside the function, it accesses the files property from the event target (e.currentTarget.files). This holds an array of uploaded files.
  • Since we typically only want to handle a single file at a time, the code grabs the first element from the files array (files[0]).
  • It then updates the React state variable setFile with the chosen file.
  • Additionally, it sets another state variable, setIsFileUploaded to true, likely to trigger a success message for the user.

  • Pass the function to onChange event in the HTML input:

<input id="dropzone-file" type="file" className="hidden" accept='.pdf, .docx, .doc, .odt' required onChange={handleFileInput}/>
Enter fullscreen mode Exit fullscreen mode

This code defines a hidden file input element that utilizes the handleFileInput function.
<input ... /> defines an HTML input element specifically for file uploads.
-id="dropzone-file": This assigns a unique identifier to the element, potentially for styling or referencing it later.
-type="file": This specifies the input type as a file upload field.
-className="hidden": This class likely hides the element from the user interface. You might use a separate dropzone component for user interaction and link this hidden input to it.
-accept='.pdf, .docx, .doc, .odt': This restricts file selection to specific formats: PDF, DOCX, DOC, and ODT.
required: This attribute enforces the user to select a file before submitting the form.
-onChange={handleFileInput}: This crucial part connects the input element to the handleFileInput function. Whenever the user selects a file, this function will be triggered to handle the chosen file.

Send the file to the server
For this, we'll use axios.

  1. Install Axios - run the following command in your terminal
    npm i axios

  2. import axios - at the top of the file
    import axios from 'axios';

  3. create a method that will handle the file submit

const handleFileSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault()

    const formData = new FormData()
    if (file) {
      formData.append('file', file)
    }

    try {
      const response = await axios.post(`your_api_endpoint`, formData, { headers: { "Content-Type": "multipart/form-data" } })
      console.log(response);

    } catch (error: unknown) {
      console.error(error);
    }
  }
Enter fullscreen mode Exit fullscreen mode

This code snippet handles submitting the form with the uploaded file.
-handleFileSubmit is an asynchronous function triggered when the form is submitted (

).
-e.preventDefault() prevents the default form submission behavior, allowing us to control the file upload process.
-const formData = new FormData() creates a new FormData object, specifically designed for handling file uploads.
-if (file) { formData.append('file', file) } checks if a file has been selected (file state variable) and if so, it adds the file to the formData object using the append method. The first argument ('file') specifies the key used on the server-side to access the file, and the second argument (file) is the actual file object.
-try...catch block handles the asynchronous nature of the file upload: try block attempts to send a POST request using axios.post. The first argument ('your_api_endpoint') is a placeholder for your actual server-side endpoint that will receive the uploaded file. The second argument (formData) is the FormData object containing the file. The third argument ({ headers: { "Content-Type": "multipart/form-data" } }) sets the Content-Type header in the request to multipart/form-data, which is essential for file uploads. catch (error) block catches any errors that might occur during the upload process and logs them to the console for debugging.
console.log(response); (within the try block) logs the server's response to the console, allowing you to inspect the outcome (potentially success message or any additional data).
In essence, this code snippet takes the uploaded file, prepares it for sending with FormData, and uses axios.post to submit it to your server-side API.
  1. Pass the handleFileSubmit method to the form <form onSubmit={handleFileSubmit}>

Conclusion

By now, you've equipped yourself with the skills to confidently integrate file uploads into your React applications. Remember, this is just the beginning! You can further enhance the user experience by adding features like drag-and-drop upload zones, progress bars, and informative error messages.
Stay Connected, Keep Learning!
If you have any questions or want to delve deeper into React development, feel free to join our WhatsApp group! We have a thriving community of developers eager to share knowledge and collaborate.

Join the WhatsApp Group

Keep up-to-date with the latest React trends and techniques. Happy coding!

Top comments (0)