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;
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>
);
}
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;
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>
);
}
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}]
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)
}
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);
}
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>
);
}
And when we upload a CSV and click submit, we should have a view like below;
If you enjoyed this How-To article, please support by Subscribing to my youtube channel https://www.youtube.com/channel/UCvF499ChQBnWb5ex162EiMg
Top comments (12)
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
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
I found this really helpful - thank you!
You’re welcome
This was very helpful, thank you Nurudeen!
This was super useful, you saved me a lot of coding. Thanks!
I had problems with the breaks and the cvsArray, can you help me
TypeError: csvArray is undefined
Check for csvArray before using it, you can put everything inside an if block
if(csvArray){
// continue
}
What’s the error you’re getting?
This is exactly what I was looking for! thank you so much :)))
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..