10

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...

1
  • What about multiple images? Commented Jun 1, 2022 at 9:50

2 Answers 2

19

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);
      }
    })
  }
Sign up to request clarification or add additional context in comments.

Comments

8

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

2 Comments

How to get a preview box of image/file after its uploaded??
@isaksham To show a preview of the image, you can add this element: <img src={this.state.image} />, where image is the file's data as a base64 encoded string. Whenever a new image file is chosen and read by FileReader.readAsDataURL(), the state will change and thus update the <img/> source.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.