42

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.

4
  • 1
    what did you tried? Commented Jun 26, 2017 at 21:40
  • @Jonnysai there are a number of packages that read files with ReactJS, but none of them seem to deal with CSV files. Commented Jun 26, 2017 at 21:44
  • Could you elaborate? "Parsing" .csv could mean a lot of things. Is the data from the .csv supposed to be formatted and displayed somehow? Commented Jun 26, 2017 at 22:36
  • @ZacCollier the parsing isn't the issue, it was getting the data in a readable format Commented Jun 26, 2017 at 22:45

6 Answers 6

32

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

4 Comments

I tried doing that and I get this error: TypeError: reader.readAsText is not a function. Any tips?
@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?
For some reason FileReader was not working, after some searching I had to use window.FileReader and that did the trick.
react-file-reader has since been deprecated (2018)
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;

2 Comments

How could you convert a uploaded .xlsx file to csv and then parse with papaparse ?
@GaboRuiz XLSX.utils.sheet_to_csv from sheet.js.
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>
      </>
    )
  }
}

Comments

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

1 Comment

"github.com/mholt/PapaParse last release was in Aug 2020." - it seems they made release in 2023
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>

Comments

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

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.