Search code examples
javascriptreactjspapaparse

How do I access the contents of a .tsv file with React and papa-parse?


Here is my App.js in the react app:

import FileUpload from './components/file-upload'

const App = () => {

  return (
          <div>
             <FileUpload />
          </div>
  );
}

export default App;

And here is my FileUpload component:

import Papa from "papaparse"

const FileUpload = (props) => {
    return (
        <main>
            <div id="fileDrop"

                onDragOver = {(e) => {
                    e.preventDefault()
                }}
                onDrop = {async(e) => {
                    e.preventDefault()
                    let dataArray = []

                    const data = await Object.values(e.dataTransfer.files).map( file => {
                        if (file.type === "text/tab-separated-values") {
                            const text = file.text()
                            text.then(text => {
                                const parsed = Papa.parse(text, {delimiter: "\t"})
                                parsed.data.forEach(row => {
                                    dataArray.push(row)
                                    return row
                                })
                            })
                        }
                    })
                    // console.log 1
                    console.log(data)
                    // console.log 2
                    console.log(dataArray)
                    // console.log 3
                    console.log(dataArray[0])
                }}
            >drag here</div>
        </main>
    )
}

export default FileUpload

The problem I'm running into is I can't seem to get access to the data from the .tsv file after I drop it. When I try to map over it and console.log the returned array (console.log 1), they just say undefined, and when I push it to dataArray and console.log that (console.log 2), I can click into it and all the data is there, but when I try to access an individual key (console.log 3), it says undefined again.

Am I using async/await correctly? Is it a problem with the file.text() promise? Thank you for your help!


Solution

  • Try looping over each file value first and filter out any files that you don't need instead of using the if statement. Then map over each file and call file.text(). This will return a Promise for each file.

    With Promise.all you can wait for all of the promises to resolve before continueing. Now it makes sense to use await as Promise.all also returns a promise (Object.values does not return a promise so awaiting it has no effect).

    When all promises resolve you should end up with an array of texts. Loop over each text with flatMap. The reason for doing this over a regular map is that Papa.parse returns an array of rows. flatMap will flatten the array of arrays to a single array of rows, as seemed the intention with the code in the question.

    const texts = await Promise.all(
      Object.values(e.dataTransfer.files)
        .filter(file => file.type === "text/tab-separated-values")
        .map(file => file.text())
    );
    
    const dataArray = texts.flatMap(text => {
      const parsed = Papa.parse(text, {delimiter: "\t"});
      return parsed.data;
    });