React提交家长端注册请求返回400 Bad Request问题排查
完成家长端用户注册操作时,即使所有表单字段都已填写,服务端仍然返回400 Bad Request错误,提示内容为please enter ...。控制台日志打印的parent对象不为空,相关截图如下:
相关代码定义
Mongoose Schema 定义
const parentSchema = new Schema({ // id: { type: String }, user: { type: Schema.Types.ObjectId, ref: "User", }, civil: { type: String }, job: { type: String }, familyMembers: { type: Number }, demandes: { type: String }, registerDate: { type: Date, default: Date.now(), }, child: [ { type: Schema.Types.ObjectId, ref: "Child", required: false, }, ], });
React端定义的parent初始对象:
{ user: { firstName: "", lastName: "", email: "", password: "", confirmPassword: "", phone: "", address: { street: "", zipCode: "", city: "", state: "", }, category: "parent", }, civil: "", job: "", familyMembers: "", demandes: "", }
封装的POST请求API代码:
export const postParent = async (value) => { try { await axios.post(`${process.env.REACT_APP_API_URL}/farah/sign-up/parent`, { ...value, }); } catch (error) { console.error(`postParent => ${error}`); } };
补充更新信息
后端路由配置
项目主路由配置:
app.use("/farah", parentRouter);
家长端注册接口路由配置:
parentRouter.post( "/sign-up/parent", userValidator, parentValidator, validation, signup );
错误定位
提交手动构造的静态对象时接口可以正常请求成功,排除后端问题。实际故障点为前端React中嵌套对象没有正确完成赋值操作,需要React嵌套对象表单值的正确赋值实现方案。
这个问题90%的情况都是嵌套状态更新时只做了浅拷贝,或者直接修改了状态对象的内层属性,React没有检测到状态变更,提交时实际发出去的对象里嵌套字段还是空值,自然过不了后端校验。按你用的状态管理方案选对应写法就行:
原生useState管理表单的正确写法
绝对不能直接写form.user.firstName = 输入值这种直接修改状态的代码,更新时必须逐层展开拷贝嵌套对象,保证每一层的引用都是新的,React才能识别到状态变化:
const [form, setForm] = useState(/* 你定义的初始parent对象 */) // 一级字段(civil、job、demandes这类)更新方法 const updateTopField = (e) => { setForm(prev => ({ ...prev, [e.target.name]: e.target.value })) } // 二级嵌套字段(user下的firstName、email、phone这类)更新方法 const updateUserField = (e) => { setForm(prev => ({ ...prev, user: { ...prev.user, [e.target.name]: e.target.value } })) } // 三级嵌套字段(user.address下的street、zipCode这类)更新方法 const updateAddressField = (e) => { setForm(prev => ({ ...prev, user: { ...prev.user, address: { ...prev.user.address, [e.target.name]: e.target.value } } })) }
如果字段多不想分开写方法,可以抽一个通用的按路径更新的工具函数,不用重复写逐层展开的逻辑。
生产环境推荐直接用表单库
复杂嵌套表单没必要自己手写状态更新逻辑,用react-hook-form或者formik这类成熟表单库可以完全规避这类赋值问题,天然支持嵌套对象字段:
以react-hook-form为例,初始化时传入你的嵌套结构默认值,注册字段时直接用点分隔的路径写法就行,状态更新、值收集都自动处理:
import { useForm } from 'react-hook-form' const { register, handleSubmit } = useForm({ defaultValues: /* 你定义的初始parent对象 */ }) // 表单元素注册字段直接写路径,不需要自己写赋值逻辑 <input {...register('user.firstName')} placeholder="名" /> <input {...register('user.address.zipCode')} placeholder="邮编" /> <input {...register('civil')} placeholder="身份" /> // 提交时直接拿到组装好的完整对象,直接传去接口就行 const onSubmit = (formData) => { postParent(formData) }
额外注意点
你的Schema里familyMembers定义的是Number类型,初始值给的是空字符串,提交前记得把这个字段转成数字类型,不然就算字段有值,类型不匹配也可能被后端校验拦截。
内容的提问来源于stack exchange,提问作者maya

