How to upload and read CSV files in React.js?
Asked Answered
C

6

41

I would like the user to upload a .csv file, and then have the browser be able to parse the data from that file. I am using ReactJS. How would this work? Thanks.

Courtney answered 26/6, 2017 at 21:36 Comment(4)
what did you tried?Lagos
@Jonnysai there are a number of packages that read files with ReactJS, but none of them seem to deal with CSV files.Courtney
Could you elaborate? "Parsing" .csv could mean a lot of things. Is the data from the .csv supposed to be formatted and displayed somehow?Lingenfelter
@ZacCollier the parsing isn't the issue, it was getting the data in a readable formatCourtney
C
31

Figured it out. A combination of react-file-reader and HTML5's FileReader (see this page).

Placed the react-file-reader bit inside of render:

<ReactFileReader handleFiles={this.handleFiles} fileTypes={'.csv'}>
    <button className='btn'>Upload</button>
</ReactFileReader>

And then this above.

handleFiles = files => {
    var reader = new FileReader();
    reader.onload = function(e) {
        // Use reader.result
        alert(reader.result)
    }
    reader.readAsText(files[0]);
}
Courtney answered 26/6, 2017 at 22:33 Comment(4)
I tried doing that and I get this error: TypeError: reader.readAsText is not a function. Any tips?Dangelo
@39fredy Make sure that the you are using readAsText on a file object (in this case, that files[0] is a file object). do you have more of your code?Courtney
For some reason FileReader was not working, after some searching I had to use window.FileReader and that did the trick.Dangelo
react-file-reader has since been deprecated (2018)Ermeena
U
23

I would use Papa Parse (https://www.npmjs.com/package/papaparse). And here is an example react component:

class FileReader extends React.Component {
  constructor() {
    super();
    this.state = {
      csvfile: undefined
    };
    this.updateData = this.updateData.bind(this);
  }

  handleChange = event => {
    this.setState({
      csvfile: event.target.files[0]
    });
  };

  importCSV = () => {
    const { csvfile } = this.state;
    Papa.parse(csvfile, {
      complete: this.updateData,
      header: true
    });
  };

  updateData(result) {
    var data = result.data;
    console.log(data);
  }

  render() {
    console.log(this.state.csvfile);
    return (
      <div className="App">
        <h2>Import CSV File!</h2>
        <input
          className="csv-input"
          type="file"
          ref={input => {
            this.filesInput = input;
          }}
          name="file"
          placeholder={null}
          onChange={this.handleChange}
        />
        <p />
        <button onClick={this.importCSV}> Upload now!</button>
      </div>
    );
  }
}

export default FileReader;
Unilingual answered 7/1, 2019 at 1:37 Comment(2)
How could you convert a uploaded .xlsx file to csv and then parse with papaparse ?Throve
@GaboRuiz XLSX.utils.sheet_to_csv from sheet.js.Loudermilk
S
2

The easiest way to upload and read csv files in React (React.js) is react-papaparse ( Home | Demo | Docs | Github ).

Look at the simply example below:

import React, { Component } from 'react'
import { CSVReader } from 'react-papaparse'

const buttonRef = React.createRef()

export default class CSVReader1 extends Component {
  handleOpenDialog = (e) => {
    // Note that the ref is set async, so it might be null at some point
    if (buttonRef.current) {
      buttonRef.current.open(e)
    }
  }

  handleOnFileLoad = (data) => {
    console.log('---------------------------')
    console.log(data)
    console.log('---------------------------')
  }

  handleOnError = (err, file, inputElem, reason) => {
    console.log(err)
  }

  handleOnRemoveFile = (data) => {
    console.log('---------------------------')
    console.log(data)
    console.log('---------------------------')
  }

  handleRemoveFile = (e) => {
    // Note that the ref is set async, so it might be null at some point
    if (buttonRef.current) {
      buttonRef.current.removeFile(e)
    }
  }

  render() {
    return (
      <>
        <h5>Basic Upload</h5>
        <CSVReader
          ref={buttonRef}
          onFileLoad={this.handleOnFileLoad}
          onError={this.handleOnError}
          noClick
          noDrag
          onRemoveFile={this.handleOnRemoveFile}
        >
          {({ file }) => (
            <aside
              style={{
                display: 'flex',
                flexDirection: 'row',
                marginBottom: 10
              }}
            >
              <button
                type='button'
                onClick={this.handleOpenDialog}
                style={{
                  borderRadius: 0,
                  marginLeft: 0,
                  marginRight: 0,
                  width: '40%',
                  paddingLeft: 0,
                  paddingRight: 0
                }}
              >
                Browe file
              </button>
              <div
                style={{
                  borderWidth: 1,
                  borderStyle: 'solid',
                  borderColor: '#ccc',
                  height: 45,
                  lineHeight: 2.5,
                  marginTop: 5,
                  marginBottom: 5,
                  paddingLeft: 13,
                  paddingTop: 3,
                  width: '60%'
                }}
              >
                {file && file.name}
              </div>
              <button
                style={{
                  borderRadius: 0,
                  marginLeft: 0,
                  marginRight: 0,
                  paddingLeft: 20,
                  paddingRight: 20
                }}
                onClick={this.handleRemoveFile}
              >
                Remove
              </button>
            </aside>
          )}
        </CSVReader>
      </>
    )
  }
}
Smithery answered 25/5, 2020 at 14:5 Comment(0)
U
1

Update May 2022

As mentioned https://github.com/GrillWork/react-file-reader is deprecated and https://github.com/mholt/PapaParse last release was in Aug 2020.

I used csv-parse https://csv.js.org/parse/ which is for Node & browser

CSB -> https://codesandbox.io/s/react-file-upload-parse-csv-09plq1?file=/src/App.tsx

App.tsx

import { ChangeEvent, useState } from "react";
import { Button, Box } from "@mui/material";
import { DataGrid } from "@mui/x-data-grid";
import UploadFileIcon from "@mui/icons-material/UploadFile";
import { parse } from "csv-parse/browser/esm/sync";

type cvsItem = {
  id: string;
  value: string;
};

const columns = [
  {
    field: "id",
    headerName: "Id"
  },
  {
    field: "value",
    headerName: "Value"
  }
];

export default function App() {
  const [csvData, setCsvData] = useState<cvsItem[]>([]);
  const [filename, setFilename] = useState("");

  const handleFileUpload = (e: ChangeEvent<HTMLInputElement>) => {
    if (!e.target.files) {
      return;
    }
    const file = e.target.files[0];
    const { name } = file;
    setFilename(name);

    const reader = new FileReader();
    reader.onload = (evt) => {
      if (!evt?.target?.result) {
        return;
      }
      const { result } = evt.target;
      const records = parse(result as string, {
        columns: ["id", "value"],
        delimiter: ";",
        trim: true,
        skip_empty_lines: true
      });
      setCsvData(records);
    };
    reader.readAsBinaryString(file);
  };

  return (
    <>
      <Button
        component="label"
        variant="outlined"
        startIcon={<UploadFileIcon />}
      >
        Upload CSV
        <input type="file" accept=".csv" hidden onChange={handleFileUpload} />
      </Button>
      <Box>{filename}</Box>
      <DataGrid
        autoHeight
        rows={csvData}
        columns={columns}
        hideFooter
        sx={{ mt: 1 }}
      />
    </>
  );
}

testFile.csv

1;one
2;two
3;three
Unstrap answered 27/5, 2022 at 10:52 Comment(1)
"github.com/mholt/PapaParse last release was in Aug 2020." - it seems they made release in 2023Glennaglennie
T
1

Here is a pure JS solution (works in React) to upload/read the contents of a CSV.

<input
  accept=".csv"
  hidden
  id="csvInput"
  onChange={() => {
    const reader = new FileReader();
    reader.onload = () => {
      // @ts-ignore
      document.getElementById('out').innerHTML = reader.result;
    };
    // start reading the file. When it is done, calls the onload event defined above.
    // @ts-ignore
    reader.readAsBinaryString(document.getElementById('csvInput').files[0]);
  }}
  type="file"
/>
<pre id="out"><p>File contents will appear here</p></pre>
Twoedged answered 18/10, 2022 at 2:20 Comment(0)
E
0

Other answers have mentioned browser based parsing using Papa Parse, I figured it was also worth mentioning gluestick (https://github.com/hotgluexyz/gluestick) which uses backend based parsing with prebuilt React components.

If you're looking to do validation on the input data or any column mapping, I'd recommend taking a look at the React components and the Python backend API packaged with it.

The repo links to a demo on CodeSandbox (https://1c1dl.csb.app/)

Electrokinetic answered 12/4, 2021 at 13:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.