
在 Remix 中,useSubmit() 可直接提交 JavaScript 对象(如 { id, product, order }),无需手动 JSON.stringify() + FormData;只需设置 encType: "application/json" 并在 action 中调用 request.json() 解析即可,更简洁、类型安全、符合现代 REST 风格。
在 remix 中,使用 usesubmit() 提交结构化对象数据时,无需将对象序列化为字符串再塞入 formdata——这是一种过时且易出错的做法。官方推荐且更优雅的方式是直接提交纯对象,并指定 json 编码类型。
✅ 正确做法:使用 application/json 编码
首先,在组件中调用 submit() 时传入普通对象,并显式设置 encType: "application/json":
const onSubmit = () => {
const updatedContact = {
name: "John Doe",
email: "",
};
const updatedOrder = {
products: [
{ id: 1, name: "Product 1", quantity: 1 },
{ id: 2, name: "Product 2", quantity: 2 },
],
total: 100,
};
// ✅ 直接提交对象,无需 JSON.stringify 或 FormData
submit(
{ id, product: updatedContact, order: updatedOrder },
{ method: "post", encType: "application/json" }
);
};
⚠️ 注意:
encType的值应为"application/json"(原文中的"appliction/json"是拼写错误,务必修正)。
✅ Action 端:用 request.json() 解析
在路由的 action 函数中,直接调用 await request.json() 即可获得已解析的 JS 对象,类型安全且语义清晰:
export const action: ActionFunction = async ({ request }) => {
const { id, product, order } = await request.json(); // ✅ 自动解析为对象
console.log({ id, product, order });
// 输出示例:
// {
// id: "123",
// product: { name: "John Doe", email: "" },
// order: {
// products: [{ id: 1, name: "Product 1", quantity: 1 }, ...],
// total: 100
// }
// }
// ✅ 后续可直接进行类型校验、数据库操作等
return json({ success: true });
};
❌ 为什么旧方式不推荐?
- 手动
JSON.stringify()+FormData增加冗余序列化/反序列化开销; -
Object.fromEntries(formData)返回的是字符串键值对,丢失原始类型(如数字变字符串、布尔值变字符串); -
encType: "multipart/form-data"本用于文件上传,纯 JSON 数据用它属于语义误用; - 无法利用 TypeScript 编译时类型推导,易引发运行时解析错误。
? 补充建议
- 在
action中始终对request.json()做异常捕获,防止恶意或格式错误请求:try { const body = await request.json(); } catch (e) { throw json({ error: "Invalid JSON" }, { status: 400 }); } - 若需同时上传文件与结构化数据,请仍使用
FormData,但此时应配合encType: "multipart/form-data"并在服务端用专用解析器(如express-fileupload或remix-upload)处理。
通过采用 JSON 原生传输,你的 Remix 表单提交将更简洁、健壮、可维护,也更贴近现代全栈开发的最佳实践。










