1
votes

I'm working on a Reactjs project where I can upload and download files.

But when I upload a file, the request PUT from Axios is completed before the file is fully uploaded to my database. I use the onUploadProgress from Axios and it shows directly 100% after I click on the upload button whereas the file is not uploaded yet.

It even seems that the upload of the file on the back side is only starts once the progress bar reaches 100%. I don't know how to correctly synchronize the progress bar with the file uploading.

My code

Front

  onUpload() {
    const data = new FormData();
    for (var i = 0; i < this.state.selectedFile.length; i++) {
      data.append("file", this.state.selectedFile[i]);
    }
    axios
      .put("http://localhost:5000/api/files/upload", data, {
        onUploadProgress: ProgressEvent => {
          this.setState({
            loaded: Math.round(
              (ProgressEvent.loaded * 100) / ProgressEvent.total
            )
          });
        }
      })
      .then(res => {
        console.log("File(s) uploaded", res);
      });
  }

Back

export const uploadFile = (req, res) => {
  const myFile = (Array.isArray(req.files.file)
    ? req.files.file
    : [req.files.file]
  ).filter(e => e);
  // upload file(s) to directory
  for (let i = 0; i < myFile.length; i++) {
    myFile[i].mv("./src/uploads/" + myFile[i].name, function(err) {
      if (err) {
        return res.status(500).send(err);
      }
    });
    // save file(s) to database
    Upload.create({
      type: myFile[i].mimetype,
      name: myFile[i].name,
      data: myFile[i].data
    });
  }
  res.send("file uploaded !");
};

By the way I'm using https://www.npmjs.com/package/express-fileupload for file upload

EDIT

  onUpload() {
    const data = new FormData();
    for (var i = 0; i < this.state.selectedFile.length; i++) {
      data.append("file", this.state.selectedFile[i]);
    }
    axios
      .post("http://localhost:5000/api/files/upload", data, {
        headers: {
          "Content-type": "multipart/form-data"
        },
        onUploadProgress: ProgressEvent => {
          this.setState({
            loaded: Math.round(
              (ProgressEvent.loaded * 100) / ProgressEvent.total
            )
          });
        }
      })
      .then(res => {
        console.log("File(s) uploaded", res);
      });
  }
2
Two things doesn't seem right for me, you're using the PUT method which is not appropriate because you're creating new entries in the DB (so prefer using POST), and you're not passing the content-type header multipart/form-data (the second one is the most important) Try using this content-type header - Mehdi Benmoha
There is no way to communicate from server to front end about the progress, unless you want to make a server call in every milisecond about the progress. I would suggest you to make progress bar to 95% in onUploadprogress event and complete the remaining when promise complete in .then event. - Sachin Vishwakarma
@MehdiBenmoha for some tests I created the upload button, usually this code is called by my submit button and the multipart/form-data is inside the form. I changed my code as you can see in my edit but nothing has changed. - akromx
@SachinVishwakarma how can I do that ? - akromx
added answer as a reply to your comment. - Sachin Vishwakarma

2 Answers

0
votes
onUpload() {
const data = new FormData();
for (var i = 0; i < this.state.selectedFile.length; i++) {
  data.append("file", this.state.selectedFile[i]);
}
axios
  .post("http://localhost:5000/api/files/upload", data, {
    headers: {
      "Content-type": "multipart/form-data"
    },
    onUploadProgress: ProgressEvent => {
      this.setState({
        loaded: 95
      });
    }
  })
  .then(res => {
   this.setState({
        loaded: 100
      });
    console.log("File(s) uploaded", res);
  });

}

0
votes

You are setting state as soon as you're hitting the API, the reason you're getting 100% as soon as the API hits. I would suggest you to pass "status = success" or "status = 201" from server side So that you can wait for a response in client side. i.e :-

onUpload() {
    const data = new FormData();
    for (var i = 0; i < this.state.selectedFile.length; i++) {
      data.append("file", this.state.selectedFile[i]);
    }
    axios
      .post("http://localhost:5000/api/files/upload", data, {
        headers: {
          "Content-type": "multipart/form-data"
        }
      })
      .then(res => {
        if(res.status === 'success') {
              onUploadProgress: ProgressEvent => {
               this.setState({
                 loaded: Math.round(
                (ProgressEvent.loaded * 100) / ProgressEvent.total
              )
           });
         }
        }
        console.log("File(s) uploaded", res);
      });
  }