Bhaa Rizik
Bhaa Rizik

Reputation: 107

Reading multiple files cotent's React JS

I'm trying to read multiple files with React.js, but my code reads only one file and doesn't read the rest. Any suggestion?

Thanks

constructor(props) {
    super(props);
    this.state = {
        files: [],
        changedFileIndex: -1,
        fileReader : null
    };
    this.fileUploaderRef = React.createRef();
}

 handleFileReader = (e)=>{
    console.log("handleFileReader")
     var content =this.state.fileReader.result;
     console.log(content);
 }

  handleFileChosen(file){
    console.log("handleFileChosen")
    console.log(file.result)
     this.state.fileReader=new FileReader();
     this.state.fileReader.onloadend = this.handleFileReader;
     this.state.fileReader.readAsText(file);   

 }


async readAllFiles (AllFiles) {
    console.log("readAllFiles")
    //console.log(AllFiles[0].name)
   AllFiles.map((file)=>
       {  
               this.handleFileChosen(file)
        }
    );

 }

In the array of files, we need to loop over the files and send to the other functions in order to write content of each file in the array. After some debugging, for example for 2 files, it looks like the code executes 'handleFileChosen' 2 times, and then goes to handleFileReader 2 times which is probably what's wrong but I'm not sure how to fix this. Instead, it should be like this: execute 'HandleFileReader', then execute 'handleFileChosen', then again 'HandleFileReader', then execute 'handleFileChosen'

Upvotes: 4

Views: 3737

Answers (2)

Khabir
Khabir

Reputation: 5862

Please find the complete code to show how to read multiple file contents. In handleUpload event I prepared AllFiles and call the function readAllFiles by passing AllFiles. Then I called readFileContents under readAllFiles that actually is reading file contents. As FileReader works asynchronously so need to use Promise here.

Here is Code Sandbox

Here is the Code:

import React, {Component} from 'react';

export default class FileReaderExample extends Component {

    readFileContents = async (file) => {
        return new Promise((resolve, reject) => {
            let fileReader = new FileReader();
            fileReader.onload = () => {
                resolve(fileReader.result);
            };
            fileReader.onerror = reject;
            fileReader.readAsText(file);
        });
    }
    readAllFiles = async (AllFiles) => {
        const results = await Promise.all(AllFiles.map(async (file) => {
            const fileContents = await this.readFileContents(file);
            return fileContents;
        }));
        console.log(results, 'resutls');
        return results;
    }

    handleUpload = (e) => {
        let AllFiles = [];
        [...e.target.files].map(file => AllFiles.push(file));

        this.readAllFiles(AllFiles).then(result => {
            let preview = document.getElementById('showText');
            let allFileContents = "";
            result.map(res =>{
                allFileContents += res + '<br/>'
            })
            preview.innerHTML = allFileContents;
        })
            .catch(err => {
                alert(err);
            });
    }

    render = () => {

        return (<div>
                <input type="file" multiple onChange={(e) => this.handleUpload(e)}/>
                <div id="showText">Choose text File</div>
            </div>
        )
    }
}

Upvotes: 0

Nagesh Sanika
Nagesh Sanika

Reputation: 1100

arr.map() is synchronous and FileReader works asynchronously, use Promise.all on the array returned by map

Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

I have modified your functions to read all files

handleFileChosen = async (file) => {
  return new Promise((resolve, reject) => {
    let fileReader = new FileReader();
    fileReader.onload = () => {
      resolve(fileReader.result);
    };
    fileReader.onerror = reject;
    fileReader.readAsText(file);
  });
}


readAllFiles = async (AllFiles) => {
  const results = await Promise.all(AllFiles.map(async (file) => {
    const fileContents = await handleFileChosen(file);
    return fileContents;
  }));
  console.log(results);
  return results;
}

Upvotes: 3

Related Questions