如何使用 FormData 和 React Hook Form 进行多部分文件上传

2025-06-10

如何使用 FormData 和 React Hook Form 进行多部分文件上传

在这个例子中,我们将学习如何使用React Hook Form上传文件,这是使用 React 管理表单的首选方法。我们将使用FormData上传文件,并将上传一个 multipart/form-data 类型的文件。

介绍

我们将逐步讲解如何使用 React Hook Form 来实现多部分文件上传,该功能通常用于将图片或文件上传到服务器。首先,我们来创建一个简单的Express服务器来上传文件。然后,我们使用 React Hook Form 将文件上传到该服务器。开始吧!

创建 Express 服务器

npm i express
Enter fullscreen mode Exit fullscreen mode

然后,让我们安装必要的 cors 包以允许文件上传到服务器,以及 express-fileupload 包来管理下载文件的路径。

npm i cors express-fileupload
Enter fullscreen mode Exit fullscreen mode

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}`));
Enter fullscreen mode Exit fullscreen mode

Express 服务器

我们使用 Express 创建了一个服务器。如您所见,我们已经成功启动了服务器,现在我们有一个端点来处理对此端口的请求。现在,让我们创建一个 React 项目,并使用 React Hook Form 将文件发送到该服务器。

创建 React 项目

让我们使用Create React App创建一个 React 项目,然后为我们的项目安装必要的包。

npx create-react-app react-hook-form-multipart-upload
Enter fullscreen mode Exit fullscreen mode

项目准备就绪后,让我们转到项目目录并安装 React Hook Form 包。

cd react-hook-form-multipart-upload
npm install react-hook-form

npm run start
Enter fullscreen mode Exit fullscreen mode

使用 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;
Enter fullscreen mode Exit fullscreen mode

为了管理表单及其元素,我们在 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;
Enter fullscreen mode Exit fullscreen mode

我们的项目已经准备好了!使用 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方法自动保存到数据库中。

这是一个使用refineheadlessCMS功能创建的基础应用。您可以使用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>
    );
};
Enter fullscreen mode Exit fullscreen mode

优化分段文件上传

如您所见,我们已使用适配器轻松地将标题、类别、状态和图片等数据以 的形式保存multipart/form-data到数据库中refine-react-hook-form。本教程仅演示了如何在示例中使用分段文件上传功能。如需查看Refine CMS 示例,请查看下方的实时代码沙盒 (codeSandbox)。

优化分段上传实时 CodeSandbox 示例

鏂囩珷鏉ユ簮锛�https://dev.to/refine/how-to-multipart-file-upload-using-formdata-with-react-hook-form-4d6d
PREV
我是如何从面试失败到在亚马逊找到工作的
NEXT
使用 refine 和 Strapi 在 15 分钟内创建反馈管理面板