如何使用 FormData 和 React Hook Form 进行多部分文件上传
在这个例子中,我们将学习如何使用React Hook Form上传文件,这是使用 React 管理表单的首选方法。我们将使用FormData上传文件,并将上传一个 multipart/form-data 类型的文件。
介绍
我们将逐步讲解如何使用 React Hook Form 来实现多部分文件上传,该功能通常用于将图片或文件上传到服务器。首先,我们来创建一个简单的Express服务器来上传文件。然后,我们使用 React Hook Form 将文件上传到该服务器。开始吧!
创建 Express 服务器
npm i express
然后,让我们安装必要的 cors 包以允许文件上传到服务器,以及 express-fileupload 包来管理下载文件的路径。
npm i cors express-fileupload
POST
我们已经完成了安装,可以创建一个简单的服务器。该服务器将响应我们指定的端点的调用,指示文件上传成功或失败。
import express from "express";
import fileupload from "express-fileupload";
import cors from "cors";
const app = express();
app.use(
fileupload({
createParentPath: true,
}),
);
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.post("/upload-file", async (req, res) => {
try {
if (!req.files) {
res.send({
status: "failed",
message: "No file uploaded",
});
} else {
let file = req.files.file;
console.log(req.files);
file.mv("./uploads/" + file.name);
res.send({
status: "success",
message: "File is uploaded",
data: {
name: file.name,
mimetype: file.mimetype,
size: file.size,
},
});
}
} catch (err) {
res.status(500).send(err);
}
});
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`Server started on port ${port}`));
我们使用 Express 创建了一个服务器。如您所见,我们已经成功启动了服务器,现在我们有一个端点来处理对此端口的请求。现在,让我们创建一个 React 项目,并使用 React Hook Form 将文件发送到该服务器。
创建 React 项目
让我们使用Create React App创建一个 React 项目,然后为我们的项目安装必要的包。
npx create-react-app react-hook-form-multipart-upload
项目准备就绪后,让我们转到项目目录并安装 React Hook Form 包。
cd react-hook-form-multipart-upload
npm install react-hook-form
npm run start
使用 React Hook Form 进行多部分文件上传
我们创建了 React 项目,并安装了 React Hook Forms 包。现在,让我们创建一个表单,并使用 React Hook Forms 进行管理。
import React from "react";
import { useForm } from "react-hook-form";
function App() {
const { register, handleSubmit } = useForm();
const onSubmit = () => {};
return (
<div className="App">
<form onSubmit={handleSubmit(onSubmit)}>
<input type="file" {...register("file")} />
<input type="submit" />
</form>
</div>
);
}
export default App;
为了管理表单及其元素,我们在 React Hook Form 中定义了 register 和 handleSubmit 方法。现在,我们将 onSubmit 方法中选择的文件放入 formData 中,上传到服务器。
import React from "react";
import { useForm } from "react-hook-form";
function App() {
const { register, handleSubmit } = useForm();
const onSubmit = async (data) => {
const formData = new FormData();
formData.append("file", data.file[0]);
const res = await fetch("http://localhost:5000/upload-file", {
method: "POST",
body: formData,
}).then((res) => res.json());
alert(JSON.stringify(`${res.message}, status: ${res.status}`));
};
return (
<div className="App">
<form onSubmit={handleSubmit(onSubmit)}>
<input type="file" {...register("file")} />
<input type="submit" />
</form>
</div>
);
}
export default App;
我们的项目已经准备好了!使用 React Hook Form,我们现在可以将选定的文件以类型形式发送到服务器multipart/form-data
。让我们测试一下!
您正在寻找 React Web 框架吗?
基于 React 的框架,用于快速构建内部工具。refine提供大量开箱即用的功能,可实现快速开发,同时又不牺牲极致的可定制性。用例包括但不限于管理面板、B2B 应用程序和仪表板。
🔥 Headless:适用于任何 UI 框架
⚙️ 零配置:Superplate 只需一行设置,不到一分钟即可启动项目。
📦开箱即用:路由、网络、身份验证、状态管理、i18n 和 UI。
🔌 后端无关:可连接到任何自定义后端。内置支持 REST API、Strapi、NestJs CRUD、Hasura、Nhost、Airtable、Supabase、Appwrite 和 Altogic。
📝 原生 Typescript 核心:您可以随时选择退出纯 JavaScript。
🐜 企业级 UI:与 Ant 设计系统无缝衔接。(对多种 UI 框架的支持已列入路线图)
📝 无样板代码:保持代码库清洁且可读。
如何使用 Refine 和 React Hook Form 进行多部分文件上传?
它允许您使用其自带的refine-react-hook-form 适配器(该适配器通过其Refine Headless功能发布)来管理表单并将数据发送到服务器。使用此适配器,您可以将 React Hook Form 的所有功能与Refine配合使用。您还可以Multipart File Upload(multipart/form-data)
使用此适配器非常轻松地执行操作。
有关详细信息,请参阅 refine-react-hook-form 适配器文档。→
您可以使用 轻松管理表单refine-react-hook-form adapter
。表单中创建的数据将通过refine onFinish
方法自动保存到数据库中。
这是一个使用refine的headlessCMS
功能创建的基础应用。您可以使用refine快速创建记录并将其保存到数据库中。我们将在本步骤中查看 CreatePost 页面。我们将在表单中创建一条记录,并使用适配器进行管理。refine-react-hook-form
Refine Create Post Page:
import { useState } from "react";
import { useForm } from "@pankod/refine-react-hook-form";
import { useSelect, useApiUrl } from "@pankod/refine-core";
import axios from "axios";
export const PostCreate: React.FC = () => {
const [isUploading, setIsUploading] = useState<boolean>(false);
const {
refineCore: { onFinish, formLoading },
register,
handleSubmit,
formState: { errors },
setValue,
} = useForm();
const apiURL = useApiUrl();
const { options } = useSelect({
resource: "categories",
});
const onSubmitFile = async () => {
setIsUploading(true);
const inputFile = document.getElementById(
"fileInput",
) as HTMLInputElement;
const formData = new FormData();
formData.append("file", inputFile?.files?.item(0) as File);
const res = await axios.post<{ url: string }>(
`${apiURL}/media/upload`,
formData,
{
withCredentials: false,
headers: {
"Access-Control-Allow-Origin": "*",
},
},
);
setValue("thumbnail", res.data.url);
setIsUploading(false);
};
return (
<form onSubmit={handleSubmit(onFinish)}>
<label>Title: </label>
<input {...register("title", { required: true })} />
{errors.title && <span>This field is required</span>}
<br />
<label>Status: </label>
<select {...register("status")}>
<option value="published">published</option>
<option value="draft">draft</option>
<option value="rejected">rejected</option>
</select>
<br />
<label>Category: </label>
<select
defaultValue={""}
{...register("category.id", { required: true })}
>
<option value={""} disabled>
Please select
</option>
{options?.map((category) => (
<option key={category.value} value={category.value}>
{category.label}
</option>
))}
</select>
{errors.category && <span>This field is required</span>}
<br />
<label>Content: </label>
<br />
<textarea
{...register("content", { required: true })}
rows={10}
cols={50}
/>
{errors.content && <span>This field is required</span>}
<br />
<br />
<label>Image: </label>
<input id="fileInput" type="file" onChange={onSubmitFile} />
<input
type="hidden"
{...register("thumbnail", { required: true })}
/>
{errors.thumbnail && <span>This field is required</span>}
<br />
<br />
<input type="submit" disabled={isUploading} value="Submit" />
{formLoading && <p>Loading</p>}
</form>
);
};
如您所见,我们已使用适配器轻松地将标题、类别、状态和图片等数据以 的形式保存multipart/form-data
到数据库中refine-react-hook-form
。本教程仅演示了如何在示例中使用分段文件上传功能。如需查看Refine CMS 示例,请查看下方的实时代码沙盒 (codeSandbox)。