Multipart Upload
We will demonstrate how to perform a multipart upload with Refine.
Let's start with the creation form
first.
Create Form
Let's add the image field to the post creation form
.
import {
useApiUrl,
} from "@refinedev/core";
import {
getValueFromEvent,
Create,
useForm,
} from "@refinedev/antd";
import {
Upload,
Form,
Input,
} from "antd";
export const PostCreate: React.FC = () => {
const { formProps, saveButtonProps } = useForm<IPost>();
const apiUrl = useApiUrl();
return (
<Create saveButtonProps={saveButtonProps}>
<Form {...formProps} layout="vertical">
<Form.Item
label="Title"
name="title"
rules={[
{
required: true,
},
]}
>
<Input />
</Form.Item>
<Form.Item label="Image">
<Form.Item
name="image"
valuePropName="fileList"
getValueFromEvent={getValueFromEvent}
noStyle
>
<Upload.Dragger
name="file"
action={`${apiUrl}/media/upload`}
listType="picture"
maxCount={5}
multiple
>
<p className="ant-upload-text">Drag & drop a file in this area</p>
</Upload.Dragger>
</Form.Item>
</Form.Item>
</Form>
</Create>
);
};
interface IPost {
id: number;
title: string;
image: [
{
uid: string;
name: string;
url: string;
status: "error" | "success" | "done" | "uploading" | "removed";
},
];
}
We can reach the API URL by using the useApiUrl
hook.
It will look like this.
We currently require an upload endpoint that accepts multipart uploads. This address should be passed into the action
property of the Upload
component.
{
"file": "binary"
}
This end-point should be Content-type: multipart/form-data
and Form Data: file: binary
.
This end-point should respond similarly.
{
"url": "https://example.com/uploaded-file.jpeg"
}
We have to use the getValueFromEvent
method to convert the uploaded files to Antd UploadFile object.
This data is sent to the API when the form is submitted.
{
"title": "Test",
"image": [
{
"uid": "rc-upload-1620630541327-7",
"name": "greg-bulla-6RD0mcpY8f8-unsplash.jpg",
"url": "https://refine.ams3.digitaloceanspaces.com/78c82c0b2203e670d77372f4c20fc0e2",
"type": "image/jpeg",
"size": 70922,
"percent": 100,
"status": "done"
}
]
}
The following data are required for the Antd Upload component and all should be saved.
Property | Description |
---|---|
uid | Unique id |
name | File Name |
url | Download URL |
status | error, success, done, uploading, removed |
Edit Form
Let's add the image field to the post editing form.
import {
useApiUrl,
} from "@refinedev/core";
import {
getValueFromEvent,
Edit,
useForm,
} from "@refinedev/antd";
import {
Upload,
Form,
Input,
} from "antd";
export const PostEdit: React.FC = () => {
const { formProps, saveButtonProps } = useForm<IPost>();
const apiUrl = useApiUrl();
return (
<Edit saveButtonProps={saveButtonProps}>
<Form {...formProps} layout="vertical">
<Form.Item
label="Title"
name="title"
rules={[
{
required: true,
},
]}
>
<Input />
</Form.Item>
<Form.Item label="Image">
<Form.Item
name="image"
valuePropName="fileList"
getValueFromEvent={getValueFromEvent}
noStyle
>
<Upload.Dragger
name="file"
action={`${apiUrl}/media/upload`}
listType="picture"
maxCount={5}
multiple
>
<p className="ant-upload-text">Drag & drop a file in this area</p>
</Upload.Dragger>
</Form.Item>
</Form.Item>
</Form>
</Edit>
);
};
The request, like the one below, is sent for the edit form.
{
"id": 1,
"title": "Test",
"image": [
{
"uid": "rc-upload-1620630541327-7",
"name": "greg-bulla-6RD0mcpY8f8-unsplash.jpg",
"url": "https://refine.ams3.digitaloceanspaces.com/78c82c0b2203e670d77372f4c20fc0e2",
"type": "image/jpeg",
"size": 70922,
"percent": 100,
"status": "done"
}
]
}
This data is sent to the API when form is submitted.
{
"title": "Test",
"image": [
{
"uid": "rc-upload-1620630541327-7",
"name": "greg-bulla-6RD0mcpY8f8-unsplash.jpg",
"url": "https://refine.ams3.digitaloceanspaces.com/78c82c0b2203e670d77372f4c20fc0e2",
"type": "image/jpeg",
"size": 70922,
"percent": 100,
"status": "done"
}
]
}
Uploading State
You may want to disable the "Save" button in the form while the upload is going on. To do this, you can use the useFileUploadState
hook.
import { useApiUrl } from "@refinedev/core";
import {
getValueFromEvent,
useFileUploadState,
Create,
useForm,
} from "@refinedev/antd";
import { Upload, Form, Input } from "antd";
export const PostCreate: React.FC = () => {
const { formProps, saveButtonProps } = useForm<IPost>();
const { isLoading, onChange } = useFileUploadState();
const apiUrl = useApiUrl();
return (
<Create
saveButtonProps={{
...saveButtonProps,
disabled: isLoading,
}}
>
<Form {...formProps} layout="vertical">
<Form.Item
label="Title"
name="title"
rules={[
{
required: true,
},
]}
>
<Input />
</Form.Item>
<Form.Item label="Image">
<Form.Item
name="image"
valuePropName="fileList"
getValueFromEvent={getValueFromEvent}
noStyle
>
<Upload.Dragger
name="file"
action={`${apiUrl}/media/upload`}
listType="picture"
maxCount={5}
multiple
onChange={onChange}
>
<p className="ant-upload-text">Drag & drop a file in this area</p>
</Upload.Dragger>
</Form.Item>
</Form.Item>
</Form>
</Create>
);
};
Example
npm create refine-app@latest -- --example upload-antd-multipart