如何实现NextJS表单提交与MongoDB关联?现有代码问题求助
解决Next.js表单与MongoDB连接问题及推荐Hooks使用
一、现有代码的核心问题
- 表单提交路径不匹配:表单
action="/api/form",但你的API路由实际是/api/products - 提交按钮未关联表单:submit按钮在
<footer>标签内,不属于<form>节点,无法触发表单提交事件 - 输入字段与模型字段不对应:模型里是
cover字段,但输入框name设为image;模型包含wallet字段,但表单未提供对应输入项 - 未阻止默认提交行为:直接将
postProduct绑定到onSubmit,未阻止浏览器默认的刷新提交逻辑,且异步提交未正确处理 - 无表单状态管理:未使用Hooks收集输入值,无法将正确的结构化数据传递给API
二、推荐使用的React Hooks
- useState:管理表单各字段的状态,方便实时收集和修改输入数据
- useCallback:优化表单提交函数,避免组件重渲染时重复创建函数(可选但推荐)
三、修改后的完整代码示例
1. 表单组件(NewProductForm.js)
import NewProductTabs from "./NewProductTabs"; import React, { useState, useCallback } from "react"; import { postProduct } from "../../../database/helpers/helpers"; export default function NewProductForm() { // 初始化表单状态,与MongoDB模型字段一一对应 const [formData, setFormData] = useState({ cover: "", title: "", description: "", url: "", price: "", wallet: "" }); // 实时更新表单输入状态 const handleInputChange = (e) => { const { name, value } = e.target; setFormData(prev => ({ ...prev, [name]: value })); }; // 表单提交处理逻辑 const handleSubmit = useCallback(async (e) => { e.preventDefault(); // 阻止浏览器默认提交行为 try { const result = await postProduct(formData); console.log("产品添加成功:", result); // 提交成功后重置表单 setFormData({ cover: "", title: "", description: "", url: "", price: "", wallet: "" }); } catch (error) { console.error("提交失败:", error); } }, [formData]); return ( <div className="flex-col gap-4"> <NewProductTabs /> <form onSubmit={handleSubmit} className="flex flex-col gap-3 border border-black p-6 pb-10" > {/* Cover image 字段,name对应模型的cover */} <div className="input-type gap-2"> <label className="flex px-5 py-2 text-sm font-semibold"> Cover image </label> <input type="text" name="cover" value={formData.cover} onChange={handleInputChange} className="w-full rounded-md border border-black px-5 py-5 text-sm shadow-brutal-sm focus:outline-none" placeholder="Image link" required /> </div> {/* Title字段 */} <div className="input-type gap-2"> <label className="flex px-5 py-2 text-sm font-semibold">Title</label> <input type="text" name="title" value={formData.title} onChange={handleInputChange} className="w-full rounded-md border border-black px-5 py-5 text-sm shadow-brutal-sm focus:outline-none" placeholder="Title" required /> </div> {/* Description字段 */} <div className="input-type"> <label className="flex px-5 py-2 text-sm font-semibold"> About Product </label> <textarea rows="6" name="description" value={formData.description} onChange={handleInputChange} className="w-full rounded-md border border-black px-5 py-5 text-sm shadow-brutal-sm focus:outline-none" placeholder="Description" required /> </div> {/* Url字段 */} <div className="input-type"> <label className="flex px-5 py-2 text-sm font-semibold">Url</label> <input type="url" name="url" value={formData.url} onChange={handleInputChange} className="w-full rounded-md border border-black px-5 py-5 text-sm shadow-brutal-sm focus:outline-none" placeholder="/url" required /> </div> {/* Price字段:模型为String类型,输入number后转字符串 */} <div className="input-type"> <label className="flex px-5 py-2 text-sm font-semibold">Price</label> <input type="number" name="price" value={formData.price} onChange={(e) => setFormData(prev => ({ ...prev, price: e.target.value.toString() }))} className="w-full rounded-md border border-black px-5 py-5 text-sm shadow-brutal-sm focus:outline-none" placeholder="Price, USDT" required /> </div> {/* Wallet字段:补充模型要求的字段 */} <div className="input-type gap-2"> <label className="flex px-5 py-2 text-sm font-semibold">Wallet Address</label> <input type="text" name="wallet" value={formData.wallet} onChange={handleInputChange} className="w-full rounded-md border border-black px-5 py-5 text-sm shadow-brutal-sm focus:outline-none" placeholder="Wallet address" required /> </div> {/* 提交按钮移至表单内部 */} <footer className="flex h-20 mt-4"> <button type="submit" className="flex w-full place-content-center bg-black p-2 text-sm font-bold" > <span className="flex items-center text-center text-white"> Add product </span> </button> </footer> </form> </div> ); }
2. 辅助函数(helpers.js)修正
原代码中response.json()未加await,会返回Promise而非实际数据,需修正:
const BASE_URL = "http://localhost:3000"; //Add new product export async function postProduct(formData) { try { const options = { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(formData), }; const response = await fetch(`${BASE_URL}/api/products`, options); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const json = await response.json(); // 添加await获取实际数据 return json; } catch (error) { console.error("提交错误:", error); throw error; // 抛出错误让组件处理 } }
3. 控制器(postProduct)优化
统一使用async/await风格,避免回调与async混用:
import Products from "../models/productModel"; //POST .../api/product async function postProduct(req, res) { try { const formData = req.body; if (!formData) { return res.status(400).json({ error: "Form data isn't provided" }); } const data = await Products.create(formData); return res.status(201).json(data); // 用201状态码表示资源创建成功 } catch (error) { console.error("添加产品错误:", error); return res.status(500).json({ error: "Error while creating product" }); } } export { postProduct };
四、关键修改说明
- 状态绑定:用
useState创建与模型匹配的表单状态对象,每个输入框绑定value和onChange实现实时数据同步 - 提交逻辑:自定义
handleSubmit函数阻止默认刷新,异步调用API并处理成功/失败场景 - 字段对齐:修正输入框
name属性,确保与MongoDB模型字段完全对应 - 按钮位置:将提交按钮移入
<form>内部,保证触发表单提交事件 - API调用优化:给
response.json()添加await,并增加HTTP状态码校验,提升错误处理能力
内容的提问来源于stack exchange,提问作者sllmn
相关产品推荐
相关产品推荐

