Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ReactJS base64 file upload

I have this function on a React component

handleChangeImage: function (evt) {
    console.log("Uploading");
    var self = this;
    var reader = new FileReader();
    var file = evt.target.files[0];

    reader.onload = function(upload) {
        self.setState({
            image: upload.target.result
        });
    };
    reader.readAsDataURL(file);
    console.log(this.state.image);
    console.log("Uploaded");
},

and is called here

<input ref="file" type="file" name="file" 
                              className="upload-file" 
                              id="file"
                              onChange={this.handleChangeImage}
                              encType="multipart/form-data" 
                              required/>

I'm trying to get the base64 string to send via AJAX to a server running Flask. The problem is everytime I select a file, it is logged as null in the console

Funny thing is, if I try to select the file a second time it now logs the whole string. I must be missing something simple...

like image 983
edwardffs Avatar asked Apr 12 '16 17:04

edwardffs


2 Answers

Try this one

Input field

              <MyTextField
                id="originalFileName"
                type="file"
                inputProps={{ accept: 'image/*, .xlsx, .xls, .csv, .pdf, .pptx, .pptm, .ppt' }}
                required
                label="Document"
                name="originalFileName"
                onChange={e => this.handleFileRead(e)}
                size="small"
                variant="standard"
              />

Read File from computer

  handleFileRead = async (event) => {
    const file = event.target.files[0]
    const base64 = await this.convertBase64(file)
    console.log(base64)
  }

Base64 Converter function

  convertBase64 = (file) => {
    return new Promise((resolve, reject) => {
      const fileReader = new FileReader();
      fileReader.readAsDataURL(file)
      fileReader.onload = () => {
        resolve(fileReader.result);
      }
      fileReader.onerror = (error) => {
        reject(error);
      }
    })
  }
like image 111
Ankit Kumar Rajpoot Avatar answered Nov 09 '22 23:11

Ankit Kumar Rajpoot


It is logged as null in the console because the state hasn't been changed at the time you print it out. When you select the file second time, the string logged in console actually belongs to the previous file you selected. The state is not yet changed to the second file you select.

Referring to React's doc:

setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value. There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains.

If you want to print the correct state, you may log it in the callback function:

self.setState({
    image: upload.target.result
}, function() {
    console.log(self.state.image);
});

This will also work as the state should be changed after the 1s delay:

reader.onload = function(upload) {
    self.setState({
        image: upload.target.result
    });
};
reader.readAsDataURL(file);    
setTimeout(function() {
  console.log(self.state.image);
}, 1000);
like image 8
Siu Avatar answered Nov 10 '22 00:11

Siu