0

I'm bit in confusion, this should be pretty obvious but I'm getting lost trying to figure everything out.

I'm creating a form with React, and the user can select a few images. My initial goal is to display the preview, but for a reason I can't understand, I can't map the array of results even though I can see with a console.log() that it's not empty

Here is how I create the array:

constructor(props) {
    super(props);
    this.state = {
        // Some other elements
        m_filename: [],
    };
}

handleMultiUpload() {

    let files = document.getElementById('multiple_files_upload');
    let files_result = [];

    for(let i = 0; i < files.files.length; i++) {
        let reader = new FileReader();
        reader.readAsDataURL(files.files[i]);
        reader.onloadend = function() {
            // console.log(reader.result);
            files_result.push({
                "id": i,
                "name": files.files[i].name,
                "img": reader.result
            });
        }
    }

    this.setState({
        m_file: files_result,
    });
}

render() {

    const { m_file } = this.state;

    // rest of my code
}

From there, when I console.log the m_file variable, it returns something looking like this:

[
  0:
    id: 0
    name: "file.jpg"
    img: "[base64 file rendered here]"
  1:
    id: 1
    name: "cat.jpg"
    img: "[base64 file rendered here]"
  ...etc
] 

I'm trying to loop through m_file by doing the following:

{
  m_file !== null && m_file.map(function(tile) {
      return (
          <li key={tile.id}>
              <img src={tile.img}/>
          </li>
      )
}

The problems are multiples:

  • m_file.length returns 0
  • As a consequence I can't manage to loop through it and display my images
  • Even though the console.log() make them show as an array, when I console.log(typeof m_file), it returns object. I guess because it's a state object, but... how can I deal with it, while I have no problem mapping through json elsewhere?

I have the feeling I'm ignoring something obvious.

Thank you in advance

1
  • 5
    FileReader is async operation, so when you setState, file_result is empty. Try to setState inside the reader.onloadend function. Commented Feb 20, 2018 at 11:29

1 Answer 1

1

From MDN:

The FileReader object lets web applications asynchronously read the contents of files (or raw data buffers) stored on the user's computer, using File or Blob objects to specify the file or data to read.

Since dealing with FileReader is asynchronous, when you setState, your variable file_result is still empty array.

One of possible solution, is call setState inside reader.onloadend function, just after pushing items to the array

let self = this;
reader.onloadend = function() {
   // console.log(reader.result);
   files_result.push({
      "id": i,
      "name": files.files[i].name,
      "img": reader.result
   });
   self.setState({
       m_file: files_result,
   });   
}

Note: this keyword would be binded to FileReader Object, so correct reference shall be kept in variable.

Here is the nice explanation of Async stuff in Javascript - https://stackoverflow.com/a/4560233/3918577

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.