React电商BuyNow组件React Hook Form+Yup验证失效求助
React Hook Form + Yup 验证失效问题修复方案
问题根源
你的表单验证失效核心原因有两个:
- 表单元素
name属性与register字段名不匹配:React Hook Form 依赖name属性关联表单控件和校验规则,比如姓名输入框设了name="thename"但register("fullname"),导致校验逻辑无法关联到正确控件。 - 未展示错误提示:即使校验触发,也没有渲染错误信息,无法直观看到验证结果。
修复步骤及代码调整
1. 统一表单控件name与register字段名
将所有表单元素的name属性修改为与Yup schema定义的字段名一致:
- 姓名输入框:
name="fullname" - 电话输入框:
name="phoneno" - 城市选择框:
name="city" - 支付方式选择框:
name="payment"
2. 为Yup规则添加自定义错误提示(可选但推荐)
给每个校验规则添加message,让错误提示更清晰:
const schema = yup.object({ fullname: yup.string().required("请输入姓名"), email: yup.string().email("请输入有效的邮箱地址").required("请输入邮箱"), address: yup.string().required("请输入收货地址"), phoneno: yup.number().required("请输入手机号").integer("手机号必须是整数").min(11, "手机号长度不能少于11位"), city: yup.string().required("请选择城市"), payment: yup.string().required("请选择支付方式") })
3. 添加错误信息渲染
在每个表单控件下方添加错误提示元素,示例:
<input name="fullname" id="name" placeholder='Name' {...register("fullname")} /> {errors.fullname && <p className="text-red-500 text-left">{errors.fullname.message}</p>}
完整修改后的代码
import React, { useEffect, useState } from 'react' import "./e.css" import { useForm } from "react-hook-form"; import { yupResolver } from "@hookform/resolvers/yup" import * as yup from "yup" export default function BuyNow(props) { const [country, setCountry] = useState([]) useEffect(() => { const getcountry = async () => { const res = await fetch("http://localhost:3000/setpk.json") const getcon = await res.json() setCountry(getcon) } getcountry() }, []) const schema = yup.object({ fullname: yup.string().required("请输入姓名"), email: yup.string().email("请输入有效的邮箱地址").required("请输入邮箱"), address: yup.string().required("请输入收货地址"), phoneno: yup.number().required("请输入手机号").integer("手机号必须是整数").min(11, "手机号长度不能少于11位"), city: yup.string().required("请选择城市"), payment: yup.string().required("请选择支付方式") }) const { register, handleSubmit, formState: { errors } } = useForm({ resolver: yupResolver(schema), mode: "onSubmit" // 默认提交时验证,符合非受控表单需求 }); const onSubmit = (data) => { console.log(data) } return ( <> <div className="details h-[90vh] bg-indigo-600 mt-20 text-indigo-400 text-center"> <h1 className='text-indigo-200'>Buy Now</h1> <form onSubmit={handleSubmit(onSubmit)}> <div className='space-y-5 mt-4 flex flex-col w-[70%] sm:w-[66%] md:w-[55%] mx-auto'> <div className="flex flex-col items-start w-full"> <input name="fullname" id="name" placeholder='Name' {...register("fullname")} className="w-full" /> {errors.fullname && <p className="text-red-500 mt-1">{errors.fullname.message}</p>} </div> <div className="flex flex-col items-start w-full"> <input name="email" id="email" placeholder='Email' className="text-indigo-400 w-full" {...register("email")} /> {errors.email && <p className="text-red-500 mt-1">{errors.email.message}</p>} </div> <div className="flex flex-col items-start w-full"> <input name="address" id="address" placeholder='Shipping Address' {...register("address")} className="w-full" /> {errors.address && <p className="text-red-500 mt-1">{errors.address.message}</p>} </div> <div className="flex flex-col items-start w-full"> <input type="number" name="phoneno" id="" placeholder='Phone No.' {...register("phoneno")} className="w-full" /> {errors.phoneno && <p className="text-red-500 mt-1">{errors.phoneno.message}</p>} </div> <div className="flex flex-col items-start w-full"> <select name="city" id="as" {...register("city")} className="w-full" > <option disabled selected value="">--City Name--</option> {country.map((countryget, i) => ( <option key={i} value={countryget.city}>{countryget.city}</option> ))} </select> {errors.city && <p className="text-red-500 mt-1">{errors.city.message}</p>} </div> <div className='flex relative w-auto flex-col items-start w-full'> <select name="payment" id="" className='thepayment basis-full w-[70%] ' {...register("payment")} > <option disabled selected value=""> --Payment Method-- </option> <option value="Credit Card">Credit Card</option> <option value="Cash on delivery">Cash on delivery</option> <option value="Bank Transfer">Bank Transfer</option> </select> <img src="http://localhost:3000/creditcard.png" alt="Credit Card" className='absolute w-10 right-5' /> {errors.payment && <p className="text-red-500 mt-1">{errors.payment.message}</p>} </div> </div> <input type="submit" className='bg-rose-600 p-2 rounded-lg font-mono text-white mt-3' /> </form> </div> <div className="pricesection h-20 bg-rose-600 fixed bottom-0 left-0 right-0 flex items-center px-1 text-rose-100 justify-evenly md:justify-around"> <h2 className='text-xl md:text-2xl md:font-bold '>Total Price</h2> <h2 className='text-2xl font-bold '>${props.totalprice}</h2> </div> </> ) }
额外说明
- 非受控表单:React Hook Form 默认就是非受控模式,通过
register绑定控件后,无需手动用useState管理输入值,完全符合需求。 - 验证触发时机:若需要用户输入时即时验证,可将
useForm的mode改为onChange或onBlur,默认onSubmit适合电商下单场景。
内容的提问来源于stack exchange,提问作者Sibty
相关产品推荐
相关产品推荐

