Multipart Upload
We will show you how to 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.
What we need now is an upload end-point that accepts multipart uploads. We write this address in 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>
)
}
A request, like the one below, is sent for 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