'react js handling file upload

I'm new to react js. I want to upload image asynchronously with react js Suppose I have this code

var FormBox = React.createClass({
  getInitialState: function () {
    return {
      photo: []
    }
  },
  pressButton: function () {
    var data = new FormData();
    data.append("photo", this.state.photo);
    // is this the correct way to get file data?
  },
  getPhoto: function (e) {
    this.setState({
      photo: e.target.files[0]
    })
  },
  render: function () {
    return (
      <form action='.' enctype="multipart/form-data">
        <input type='file'  onChange={this.getPhoto}/>
        <button onClick={this.pressButton}> Get it </button>
      </form>
    )
  }
})

ReactDOM.render(<FormBox />, document.getElementById('root'))

Any answer will be appreciated!



Solution 1:[1]

If you are planning to upload files using node and express then you have to create both server and client. The server has the api and the client is going to use that for uploading the file with axios.

  • Server part

First, we want to put in four packages that are express, explicit-fileupload,cors and nodemon. Run the below command to install applications.

npm i express express-fileupload cors nodemon

Now open the fileupload folder in your favorite code editor and create a brand new document referred to as server.js.

// server.js
const express = require('express');
const fileUpload = require('express-fileupload');
const cors = require('cors')
const app = express();
// middle ware
app.use(express.static('public')); //to access the files in public folder
app.use(cors()); // it enables all cors requests
app.use(fileUpload());
// file upload api
app.post('/upload', (req, res) => {
    if (!req.files) {
        return res.status(500).send({ msg: "file is not found" })
    }
        // accessing the file
    const myFile = req.files.file;
    //  mv() method places the file inside public directory
    myFile.mv(`${__dirname}/public/${myFile.name}`, function (err) {
        if (err) {
            console.log(err)
            return res.status(500).send({ msg: "Error occured" });
        }
        // returing the response with file path and name
        return res.send({name: myFile.name, path: `/${myFile.name}`});
    });
})
app.listen(4500, () => {
    console.log('server is running at port 4500');
})

use node server.js to start the server running.

  • Client

Open the react app folder on your favorite code editor and create a brand new report known as fileupload.js within the src folder. Now upload the following code.

// fileupload.js
import React, { useRef, useState } from 'react';
import axios from 'axios';
function FileUpload() {
    const [file, setFile] = useState(''); // storing the uploaded file    
    // storing the recived file from backend
    const [data, getFile] = useState({ name: "", path: "" });    
    const [progress, setProgess] = useState(0); // progess bar
    const el = useRef(); // accesing input element
    const handleChange = (e) => {
        setProgess(0)
        const file = e.target.files[0]; // accesing file
        console.log(file);
        setFile(file); // storing file
    }
    const uploadFile = () => {
        const formData = new FormData();        
        formData.append('file', file); // appending file
        axios.post('http://localhost:4500/upload', formData, {
            onUploadProgress: (ProgressEvent) => {
                let progress = Math.round(
                ProgressEvent.loaded / ProgressEvent.total * 100) + '%';
                setProgess(progress);
            }
        }).then(res => {
            console.log(res);
            getFile({ name: res.data.name,
                     path: 'http://localhost:4500' + res.data.path
                   })
        }).catch(err => console.log(err))}
    return (
        <div>
            <div className="file-upload">
                <input type="file" ref={el} onChange={handleChange} />                
                <div className="progessBar" style={{ width: progress }}>
                   {progress}
                </div>
                <button onClick={uploadFile} className="upbutton">                   
                    Upload
                </button>
            <hr />
            {/* displaying received video*/}
            {data.path && <video src={data.path} autoPlay controls />}
            </div>
        </div>
    );
}
export default FileUpload;

Now import the FileUpload component inside the App.js file.

// App.js
import React from 'react';
import FileUpload from './fileupload';
import './App.css';
function App() {
  return (
    <div className="App">
      <FileUpload />
    </div >
  );
}
export default App;

Start the react app by running npm start.

For more: React File Upload Demo

Solution 2:[2]

import axios from 'axios';
var FormBox = React.createClass({
  getInitialState: function () {
    return {
      photo: [],
      name : '',
      documents:[]
    }
  },
  pressButton: function () {
    var component = this
    var data = new FormData();
    data.append("photo", component.state.photo, component.state.name);
    var request = axios.post('http://localhost:3000/document', data)
        request.then(function(response){
    // you need to send data from server in response
          if(response.status == 200){
             console.log('saved in db')
             component.state.documents.push(response.data.documents)
             // pushed document data in documents array
           }
        })


  },
  getPhoto: function () {
    var uploadfile = document.getElementById(upload_doc).files[0]
    this.setState({
      photo: uploadfile, name : uploadfile.name
    })
  },
  render: function () {
    var documents = this.state.documents.map((doc)=>{
       return <div>
                <a href={doc.url}>{doc.name}</a>
                <img src={doc.photo} />
              </div>
    })
   // you can show your documents uploaded this way using map function
    return (
      <form action='.' enctype="multipart/form-data">
        <input type='file' id='upload_doc'  onChange={this.getPhoto}/>
        <button onClick={this.pressButton}> Get it </button>
        <span>{documents}</span>
        // this way you can see uploaded documents
      </form>
    )
  }
})

ReactDOM.render(<FormBox />, document.getElementById('root'))

Solution 3:[3]

One more easier way, by using using axios node module axios-fileupload

npm install --save axios-fileupload

const axiosFileupload = require('axios-fileupload'); 
axiosFileupload(url,file);

Solution 4:[4]

You can use React Dropzone Uploader, which gives you a dropzone that shows file previews (including image thumbnails) for dropped or chosen files, and also handles uploads for you.

import 'react-dropzone-uploader/dist/styles.css'
import Dropzone from 'react-dropzone-uploader'

const Uploader = () => {  
  return (
    <Dropzone
      getUploadParams={() => ({ url: 'https://httpbin.org/post' })} // specify upload params and url for your files
      onChangeStatus={({ meta, file }, status) => { console.log(status, meta, file) }}
      onSubmit={(files) => { console.log(files.map(f => f.meta)) }}
      accept="image/*,audio/*,video/*"
    />
  )
}

Uploads have progress indicators, and they can be cancelled or restarted. The UI is totally customizable, and the library has no dependencies.

Full disclosure: I wrote this library.

Solution 5:[5]

Use following module to select images.
https://www.npmjs.com/package/react-image-uploader

You can then upload image to server using xhr request. Following is the sample code.

var xhr  = new XMLHttpRequest();
xhr.onload = function (e) {
//your success code goes here
}
var formData = new FormData();
xhr.open("POST", url, true);
formData.append('file', fileData);
xhr.send(formData);

Solution 6:[6]

You can use whatwg-fetch to make a post request. In your pressButton() function make the following changes -

import 'whatwg-fetch';
//....

pressButton: function (url) {
    var data = new FormData();
    data.append("photo", this.state.photo);

    var options = {
      body: data,
      timeout: 3000 * 60 * 60
    };

    let callOptions = {
      method : 'POST',
      headers : {
        'Content-Type': 'application/json'
      },
      body : JSON.stringify(options.body)
    }

    return fetch(url, callOptions).then(response => response.json());
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Codemaker
Solution 2
Solution 3 Anil
Solution 4 kylebebak
Solution 5 Marzieh Mousavi
Solution 6 krhitesh