DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Cover image for Read CSV Files in React Apps without Installing Any Package
Nurudeen Amedu
Nurudeen Amedu

Posted on

Read CSV Files in React Apps without Installing Any Package

This article covers how you can read any CSV file in your React app without the need for an npm package installation.

If you would prefer a video walkthrough, check it out on YouTube;

Read CSV Files in React Apps without Installing Any Package

To try this out you need a react app, you can use an existing one or create a new app with;

npx create-react-app csv-reader

After the app setup is complete, create a component in the src folder called CsvReader.jsx

Inside it we'll be adding a basic form that accepts a csv file input and sets it to a csvFile state, and a submit button that does nothing for now. The code should look like below;

import { useState } from 'react'

export default function CsvReader(){
    const [csvFile, setCsvFile] = useState();

    return(
        <form id='csv-form'>
            <input
                type='file'
                accept='.csv'
                id='csvFile'
                onChange={(e) => {
                    setCsvFile(e.target.files[0])
                }}
            >
            </input>
            <br/>
            <button>
                Submit
            </button>
        </form>
    );

}
Enter fullscreen mode Exit fullscreen mode

You can preview by plugging it into a page in your react app, I'll simply replace my app content with the csv reader component;

import CsvReader from './CsvReader'
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <CsvReader />
      </header>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Next, we add a submit button click handler, this addition will read the CSV file when the button is clicked using the FileReader objects and log the value of our csv file as text in the browser console.

import { useState } from 'react'

export default function CsvReader(){
    const [csvFile, setCsvFile] = useState();

    const submit = () => {
        const file = csvFile;
        const reader = new FileReader();

        reader.onload = function(e) {
            const text = e.target.result;
            console.log(text);
        }

        reader.readAsText(file);
    }

    return(
        <form id='csv-form'>
            <input
                type='file'
                accept='.csv'
                id='csvFile'
                onChange={(e) => {
                    setCsvFile(e.target.files[0])
                }}
            >
            </input>
            <br/>
            <button
                onClick={(e) => {
                    e.preventDefault()
                    if(csvFile)submit()
                }}>
                Submit
            </button>
        </form>
    );

}
Enter fullscreen mode Exit fullscreen mode

Finally I will be breaking the csv text into an array of objects with each column and row data as key value pairs;
imagine we have a csv like below;

name rank age
Peter Senior 21
Joey Junior 20
Sarah Veteran 33

I want to convert it into the following;

[{name: "Peter", rank: "Senior", age: 21},
{name: "Joey", rank: "Junior", age: 20},
{name: "Sarah", rank: "Veteran", age: 33}]
Enter fullscreen mode Exit fullscreen mode

To do this we need a function that takes the plain text read from the CSV, parses it and converts into the format above, then set it to a csvArray state which we create before writing the function;

const [csvArray, setCsvArray] = useState([]);

const processCSV = (str, delim=',') => {
        const headers = str.slice(0,str.indexOf('\n')).split(delim);
        const rows = str.slice(str.indexOf('\n')+1).split('\n');

        const newArray = rows.map( row => {
            const values = row.split(delim);
            const eachObject = headers.reduce((obj, header, i) => {
                obj[header] = values[i];
                return obj;
            }, {})
            return eachObject;
        })

        setCsvArray(newArray)
    }
Enter fullscreen mode Exit fullscreen mode

This function gets called after the console.log done in the submit handler

const submit = () => {
        const file = csvFile;
        const reader = new FileReader();

        reader.onload = function(e) {
            const text = e.target.result;
            console.log(text);
            processCSV(text) // plugged in here
        }

        reader.readAsText(file);
    }
Enter fullscreen mode Exit fullscreen mode

Finally we want to display the csv data in a table on our web page, we can do this by mapping the csvArray state into a table, our final CsVReader component should look like;

import { useState } from 'react'

export default function CsvReader(){
    const [csvFile, setCsvFile] = useState();
    const [csvArray, setCsvArray] = useState([]);
    // [{name: "", age: 0, rank: ""},{name: "", age: 0, rank: ""}]

    const processCSV = (str, delim=',') => {
        const headers = str.slice(0,str.indexOf('\n')).split(delim);
        const rows = str.slice(str.indexOf('\n')+1).split('\n');

        const newArray = rows.map( row => {
            const values = row.split(delim);
            const eachObject = headers.reduce((obj, header, i) => {
                obj[header] = values[i];
                return obj;
            }, {})
            return eachObject;
        })

        setCsvArray(newArray)
    }

    const submit = () => {
        const file = csvFile;
        const reader = new FileReader();

        reader.onload = function(e) {
            const text = e.target.result;
            console.log(text);
            processCSV(text)
        }

        reader.readAsText(file);
    }

    return(
        <form id='csv-form'>
            <input
                type='file'
                accept='.csv'
                id='csvFile'
                onChange={(e) => {
                    setCsvFile(e.target.files[0])
                }}
            >
            </input>
            <br/>
            <button
                onClick={(e) => {
                    e.preventDefault()
                    if(csvFile)submit()
                }}
            >
                Submit
            </button>
            <br/>
            <br/>
            {csvArray.length>0 ? 
            <>
                <table>
                    <thead>
                        <th>Name</th>
                        <th>Age</th>
                        <th>Rank</th>
                    </thead>
                    <tbody>
                        {
                            csvArray.map((item, i) => (
                                <tr key={i}>
                                    <td>{item.name}</td>
                                    <td>{item.age}</td>
                                    <td>{item.rank}</td>
                                </tr>
                            ))
                        }
                    </tbody>
                </table>
            </> : null}
        </form>
    );

}
Enter fullscreen mode Exit fullscreen mode

And when we upload a CSV and click submit, we should have a view like below;
Final Web Page Result

If you enjoyed this How-To article, please support by Subscribing to my youtube channel https://www.youtube.com/channel/UCvF499ChQBnWb5ex162EiMg

Top comments (12)

Collapse
agusgarcia3007 profile image
Agustin Garcia

hey! could you solve the extra blank item in rows bug? I'm having the same problem

0: {name: 'joey', age: '21', rank: 'senior'}
1: {name: 'amanda', age: '28', rank: 'mid'}
2: {name: 'peter', age: '24', rank: 'junior'}
3: {name: '', age: undefined, rank: undefined

Collapse
theallegrarr profile image
Nurudeen Amedu Author

It could be due to a blank row in your csv, but it can be solved by checking the final data for undefined values and removing the row

Collapse
hannahgooding profile image
Hannah Gooding

I found this really helpful - thank you!

Collapse
theallegrarr profile image
Nurudeen Amedu Author

You’re welcome

Collapse
omogbai profile image
Omogbai Atakpu

This was very helpful, thank you Nurudeen!

Collapse
adeldegan profile image
Al Del Degan

This was super useful, you saved me a lot of coding. Thanks!

Collapse
alarbelaez profile image
alarbelaez

I had problems with the breaks and the cvsArray, can you help me

Collapse
alarbelaez profile image
alarbelaez

TypeError: csvArray is undefined

Collapse
theallegrarr profile image
Nurudeen Amedu Author

Check for csvArray before using it, you can put everything inside an if block

if(csvArray){
// continue
}

Collapse
theallegrarr profile image
Nurudeen Amedu Author

What’s the error you’re getting?

Collapse
agusgarcia3007 profile image
Agustin Garcia

This is exactly what I was looking for! thank you so much :)))

Collapse
nkrgangavaram profile image
nkrgangavaram

Heyy it was a great solution...can we get the same thing without using input type as file. Can you please help me with other ways..

🌚 Life is too short to browse without dark mode