Recentemente tive que implementar uma feature onde era necessário transformar dados que vinham de uma API (json) para csv, eu vi uma boa lib para fazer isso, react-csv, é uma lib que resolveu o problema, porém quando fui dar uma olhada no github dessa lib, vi que o último commit foi há mais de 2 anos, isso me preocupou um pouco, além disso, tem mais de 100 issues abertas.
Tendo isso em mente resolvi dar uma estudada na lib e percebi que poderia implementar na mão e de forma optimizada, além de que se acontecer algum bug eu mesmo posso resolver o problema em algumas horas.
Dito isso, bora para a implementação que é bem tranquila de ser feita:
import React from "react";
const ExportCSV = ({ data, fileName, children, headers }) => {
const downloadCSV = () => {
const csvString = [
headers,
...data.map((item) =>
headers.map((header) => {
const value = item[header];
return typeof value === "string" && value.includes(",")
? `"${value}"`
: value;
})
),
]
.map((row) => row.join(","))
.join("\n");
const blob = new Blob([csvString], { type: "text/csv" });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = fileName || "download.csv";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
};
return (
<button onClick={downloadCSV}>
{children}
</button>
);
};
export default ExportCSV;
Vamos para algumas explicações dentro da função downloadCSV recebemos os headers da tabela, também usamos o data que recebe o json a ser convertido e distribuído por cada coluna.
Tive que adicionar esse trecho de código, pois estava gerando um bug quando recebia um valor número que incluia uma vírgula, por exemplo, R$ 10.544,53.
return typeof value === "string" && value.includes(",")
? `"${value}"`
: value;
Esse bug acontecia, pois eu precisava usar o método join para remover as vírgulas e por em cada casa dentro do arquivo csv. Também usei a API nativa Blob para transformar o meu json para csv.
No fim retorno um componente react que recebe quatro propriedades, data: dados da API, headers: cabeçalho do csv, filename: nome do arquivo que tu vai querer usar, children: podendo colocar um componente aqui ou uma simples string.
Para usar esse componente é bem simples:
<CsvButton data={data} fileName="file-name.csv" headers={headers}>
<>Export data</>
</CsvButton>
Bem é isso, espero que tenham gostado e se ajudar deixe compartilhe esse post com mais alguém, e se tem algo para melhorar qualquer feedback é muito bem-vindo, obrigado.