NextJS中react-hook-form+Yup验证合法字段仍触发错误
问题:NextJS中react-hook-form结合Yup验证嵌套字段时,已填值仍提示必填错误
在NextJS项目中使用react-hook-form配合Yup做表单验证,表单包含clientInformation下的嵌套字段(如name.firstName、email),输入符合要求的数据后,依然收到"Email is required"、"First name is required"等必填项错误提示。
简化后的表单组件代码
"use client"; import { useForm } from "react-hook-form"; import { yupResolver } from "@hookform/resolvers/yup"; import validationSchema from "@/app/lib/validationSchema.js"; import { useEffect } from "react"; import { initialState } from "@/app/lib/initialState"; export default function ClientInformation() { const { register, handleSubmit, watch, control, formState: { errors }, } = useForm({ resolver: yupResolver(validationSchema), defaultValues: initialState, }); const allFormValues = watch(); const onSubmit = (data) => { console.log(data); }; useEffect(() => { console.log("Current Form Values:", allFormValues); console.log("Current Form Errors:", errors); }, [allFormValues, errors]); return ( <form onSubmit={handleSubmit(onSubmit)} className="space-y-2 divide-y divide-gray-900/10" > <div className="grid grid-cols-1 gap-x-2 gap-y-8 pt-2 md:grid-cols-3"> <div className="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2"> <div className="px-8 py-2 sm:p-8"> <div className="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-3"> <div className="sm:col-span-3"> <label htmlFor="first-name" className="block text-sm font-medium leading-6 text-gray-900" > First name </label> <div className="mt-2"> <input type="text" name="clientInformation.name.firstName" id="first-name" {...register("clientInformation.name.firstName")} autoComplete="given-name" className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" /> {errors.clientInformation?.name?.firstName && ( <p className="mt-2 text-sm text-red-600"> {errors.clientInformation.name.firstName.message} </p> )} </div> </div> <div className="sm:col-span-4"> <label htmlFor="email" className="block text-sm font-medium leading-6 text-gray-900" > Email address </label> <div className="mt-2"> <input id="email" name="clientInformation.email" type="email" {...register("clientInformation.email")} autoComplete="email" className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" /> {errors.clientInformation?.email && ( <p className="mt-2 text-sm text-red-600"> {errors.clientInformation.email.message} </p> )} </div> </div> </div> </div> </div> </div> <div className="flex justify-end p-6"> <button type="submit" className="inline-flex justify-center px-4 py-2 text-sm font-medium text-white bg-blue-600 border border-transparent rounded-md shadow-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" > Submit </button> </div> </form> ); }
验证Schema(validationSchema.js)
import * as Yup from "yup"; const validationSchema = Yup.object().shape({ "clientInformation.name.firstName": Yup.string() .trim() .min(2, "First name must be at least 2 characters") .max(30, "First name must be less than 50 characters") .required("First name is required"), "clientInformation.email": Yup.string() .email("Invalid email") .required("Email is required"), });
控制台输出
错误输出
{ "clientInformation": { "email": { "message": "Email is required", "type": "optionality", "ref": "undefined" }, "name": { "firstName": { "message": "First name is required", "type": "optionality", "ref": "undefined" } } } }
表单值输出
{ "clientInformation": { "email": "gg@gg.com", "name": { "firstName": "gggg" } // 其他字段... } }
解决方案
修正Yup Schema的嵌套结构定义
原Schema使用字符串路径定义嵌套字段,易导致react-hook-form与Yup的解析匹配异常,改为嵌套对象方式定义:import * as Yup from "yup"; const validationSchema = Yup.object().shape({ clientInformation: Yup.object().shape({ name: Yup.object().shape({ firstName: Yup.string() .trim() .min(2, "First name must be at least 2 characters") .max(30, "First name must be less than 50 characters") .required("First name is required"), }), email: Yup.string() .email("Invalid email") .required("Email is required"), }), });确保initialState结构完整
确认initialState中嵌套对象都被正确初始化,避免undefined引发验证问题:export const initialState = { clientInformation: { name: { firstName: "", }, email: "", // 其他字段... }, };显式设置shouldUnregister选项
在NextJS环境下,显式声明shouldUnregister: false(默认值),避免组件注册行为异常:const { register, handleSubmit, watch, control, formState: { errors }, } = useForm({ resolver: yupResolver(validationSchema), defaultValues: initialState, shouldUnregister: false, });标记组件为Client Component
在表单组件文件顶部添加"use client";,确保组件在客户端运行,因为react-hook-form依赖客户端状态管理:"use client";
内容的提问来源于stack exchange,提问作者DeeK
相关产品推荐
相关产品推荐

