CSV Import
You can easily import CSV files for any resource by using refine's customizable useImport
hook, optionally with <ImportButton>
component. useImport
hook returns the necessary props for <ImportButton>
component. refine uses Papa Parse parser under the hood to parse CSV files.
You can call the useImport
hook and add an <ImportButton>
with properties returned from useImport
Β on a list page, configured with a mapping function to format the files data into API's data. When the button gets triggered, it creates the imported resources using create
or createMany
dataProvider methods under the hood.
Usageβ
Let's look at an example of adding a custom import button:
import {
List,
useTable,
useMany,
useImport,
ImportButton,
} from "@pankod/refine";
export const PostList: React.FC = () => {
const { tableProps } = useTable<IPost>();
const categoryIds =
tableProps?.dataSource?.map((item) => item.category.id) ?? [];
const { data, isLoading } = useMany<ICategory>({
resource: "categories",
ids: categoryIds,
queryOptions: {
enabled: categoryIds.length > 0,
},
});
const importProps = useImport<IPostFile>();
return (
<List
pageHeaderProps={{
extra: <ImportButton {...importProps} />,
}}
>
...
</List>
);
};
interface ICategory {
id: string;
title: string;
}
interface IPostFile {
id: string;
title: string;
content: string;
userId: number;
categoryId: number;
status: "published" | "draft" | "rejected";
}
interface IPost {
id: string;
title: string;
content: string;
status: "published" | "draft" | "rejected";
category: ICategory;
}
We should map CSV data into Post
data. Assume that this is the CSV file content we have:
"title","content","status","categoryId","userId"
"dummy title 1","dummy content 1","rejected","3","8"
"dummy title 2","dummy content 2","draft","44","8"
"dummy title 3","cummy content 3","published","41","10"
It has 3 entries. We should map categoryId
Β to category.id
and userId
to user.id
. Since these are objects, we store any relational data as their id in CSV.
This would make our useImport
call look like this:
export const PostList: React.FC = () => {
const { tableProps } = useTable<IPost>();
const categoryIds =
tableProps?.dataSource?.map((item) => item.category.id) ?? [];
const { data, isLoading } = useMany<ICategory>({
resource: "categories",
ids: categoryIds,
queryOptions: {
enabled: categoryIds.length > 0,
},
});
const importProps = useImport<IPostFile>({
mapData: (item) => {
return {
title: item.title,
content: item.content,
status: item.status,
category: {
id: item.categoryId,
},
user: {
id: item.userId,
},
};
},
});
return <></>;
}
And it's done. When you click on the button and provide a CSV file of the headers "title"
,"content"
,"status"
,"categoryId"
and "userId"
, it should be mapped and imported. Mapped data is the request payload. Either as part of an array or by itself as part of every request. In our example, it fires POST
request/requests like this:
{
"title": "dummy title 1",
"content": "dummy content 1",
"status": "rejected",
"category": {
"id": "3"
},
"user": {
"id": "8"
}
}
Depending on the batchSize
option, posts can get sent one by one or as batches. By default, all records are sent in one createMany
call.