Uploading Files with React (POST Request)
Tags: webdev, react, reactjsdevelopment, forms
Published: 2024-05-01 13:57:26

**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>
  )
}
```

open your terminal and run:
`npm run dev`

you should see something similar to this

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oy1xvy380z039gfujqyz.png)



Open the port on your browser and you should see

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nikkr8vm478fg7654ljy.png)



**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>
  )
}
```

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>}
```


**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)
  } 
```

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}/>
```

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);
    }
  }
```

This code snippet handles submitting the form with the uploaded file.
-`handleFileSubmit` is an asynchronous function triggered when the form is submitted (<form onSubmit={handleFileSubmit}>).
-`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.

4.  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](https://chat.whatsapp.com/Iyv3qoHzM3P0I3M0wds9dF)

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