CSV Import - Export
Importing and exporting data are essential tasks for managing information in data extensive applications. With CSV
export and import, we can speed up the process of data entry and data migration.
Refine provides useImport
and useExport
hooks for both bulk importing and exporting data, making it easy to move large datasets between your application and external sources.
Import
useImport
hook allows you to import data from a CSV
file. For each row in the file, it calls the create
or createMany
method of your data provider according to your configuration.
Internally, it uses Papa Parse to parse the file contents.
import React, { useState } from "react";
import { useImport, useList } from "@refinedev/core";
export const HomePage = () => {
const { data } = useList({
resource: "products",
sorters: [{ field: "id", order: "desc" }],
});
const products = data?.data;
const [importProgress, setImportProgress] = useState({
processed: 0,
total: 0,
});
const { inputProps, isLoading } = useImport<IProduct>({
resource: "products",
onFinish: () => {
alert("Import completed!");
},
onProgress: (progress) => {
setImportProgress({
processed: progress.processedAmount,
total: progress.totalAmount,
});
},
});
return (
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "flex-start",
padding: "16px",
}}
>
<div style={{ display: "flex", alignItems: "center", gap: "16px" }}>
<h2>Products</h2>
<label
style={{
display: "flex",
alignItems: "center",
gap: "8px",
cursor: "pointer",
padding: "8px",
border: "1px solid #ccc",
borderRadius: "4px",
}}
>
{isLoading ? (
<p>
{importProgress.processed} / {importProgress.total}
</p>
) : (
<p>Import CSV</p>
)}
<input name="csv" {...inputProps} />
</label>
</div>
{products?.map((product) => (
<div key={product.id}>
<h4>
[ID: {product.id}] - {product.name}
</h4>
<p>{product.description}</p>
</div>
))}
</div>
);
};
interface IProduct {
id: string;
name: string;
description: string;
material: string;
price: number;
category: {
id: string;
};
}
Dependencies: @refinedev/core@latest,@refinedev/simple-rest@latest
Code Files
File: /App.tsx
Content: import React from "react";
import { Refine } from "@refinedev/core";
import dataProvider from "@refinedev/simple-rest";
import { HomePage } from "./home-page";
const API_URL = "https://api.fake-rest.refine.dev";
const App: React.FC = () => {
return (
<Refine
dataProvider={dataProvider("https://api.fake-rest.refine.dev")}
resources={[
{
name: "products",
},
]}
>
<HomePage />
</Refine>
);
};
export default App;
File: /home-page.tsx
Content: import React, { useState } from "react";
import { useImport, useList } from "@refinedev/core";
export const HomePage = () => {
const { data } = useList({
resource: "products",
sorters: [{ field: "id", order: "desc" }],
});
const products = data?.data;
const [importProgress, setImportProgress] = useState({
processed: 0,
total: 0,
});
const { inputProps, isLoading } = useImport<IProduct>({
resource: "products",
onFinish: () => {
alert("Import completed!");
},
onProgress: (progress) => {
setImportProgress({
processed: progress.processedAmount,
total: progress.totalAmount,
});
},
});
return (
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "flex-start",
padding: "16px",
}}
>
<div style={{ display: "flex", alignItems: "center", gap: "16px" }}>
<h2>Products</h2>
<label
style={{
display: "flex",
alignItems: "center",
gap: "8px",
cursor: "pointer",
padding: "8px",
border: "1px solid #ccc",
borderRadius: "4px",
}}
>
{isLoading ? (
<p>
{importProgress.processed} / {importProgress.total}
</p>
) : (
<p>Import CSV</p>
)}
<input name="csv" {...inputProps} />
</label>
</div>
{products?.map((product) => (
<div key={product.id}>
<h4>
[ID: {product.id}] - {product.name}
</h4>
<p>{product.description}</p>
</div>
))}
</div>
);
};
interface IProduct {
id: string;
name: string;
description: string;
material: string;
price: number;
category: {
id: string;
};
}
You can use the following CSV
file to test the import feature.
name,material,description,price,category
"Test Product 1","Test Material 1","Test Description 1","100","{""id"":1}"
"Test Product 2","Test Material 2","Test Description 2","200","{""id"":2}"
"Test Product 3","Test Material 3","Test Description 3","300","{""id"":3}"
Refine also provides <ImportButton />
. It's compatible with useImport
hook to easily handle the import process.
Export
useExport
hook allows you to export data as a CSV
file. It calls the getList
method of your data provider and downloads the data as a CSV
file.
Internally, it uses Papa Parse to create the CSV
file.
🚨 The download feature for CSV
files does not function within an iframe (live-previews). You can copy the code and run it in your own project to see it in action.
import React from "react";
import { useExport, useList } from "@refinedev/core";
export const HomePage = () => {
const { data } = useList({ resource: "products" });
const products = data?.data;
const { triggerExport, isLoading } = useExport<IProduct>({
resource: "products",
mapData: (item) => {
return {
...item,
category: JSON.stringify(item.category),
};
},
});
return (
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "flex-start",
padding: "16px",
}}
>
<div style={{ display: "flex", alignItems: "center", gap: "16px" }}>
<h2>Products</h2>
<button onClick={triggerExport} disabled={isLoading}>
{isLoading ? "Exporting..." : "Export Products"}
</button>
</div>
{products?.map((product) => (
<div key={product.id}>
<h4>[ID: {product.id}] - {product.name}</h4>
<p>{product.description}</p>
</div>
))}
</div>
);
};
interface IProduct {
id: string;
name: string;
description: string;
material: string;
price: number;
category: {
id: string;
};
}
Dependencies: @refinedev/core@latest,@refinedev/simple-rest@latest
Code Files
File: /App.tsx
Content: import React from "react";
import { Refine } from "@refinedev/core";
import dataProvider from "@refinedev/simple-rest";
import { HomePage } from "./home-page";
const API_URL = "https://api.fake-rest.refine.dev";
const App: React.FC = () => {
return (
<Refine
dataProvider={dataProvider("https://api.fake-rest.refine.dev")}
resources={[
{
name: "products",
},
]}
>
<HomePage />
</Refine>
);
};
export default App;
File: /home-page.tsx
Content: import React from "react";
import { useExport, useList } from "@refinedev/core";
export const HomePage = () => {
const { data } = useList({ resource: "products" });
const products = data?.data;
const { triggerExport, isLoading } = useExport<IProduct>({
resource: "products",
mapData: (item) => {
return {
...item,
// category is an object, we need to stringify it
category: JSON.stringify(item.category),
};
},
});
return (
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "flex-start",
padding: "16px",
}}
>
<div style={{ display: "flex", alignItems: "center", gap: "16px" }}>
<h2>Products</h2>
<button onClick={triggerExport} disabled={isLoading}>
{isLoading ? "Exporting..." : "Export Products"}
</button>
</div>
{products?.map((product) => (
<div key={product.id}>
<h4>[ID: {product.id}] - {product.name}</h4>
<p>{product.description}</p>
</div>
))}
</div>
);
};
interface IProduct {
id: string;
name: string;
description: string;
material: string;
price: number;
category: {
id: string;
};
}
Refine also provides <ExportButton />
. It's compatible with useExport
hook to easily handle the export process.