如何实现自定义可复用useForm钩子的提交验证并修复首次验证异常?
自定义useForm钩子验证逻辑修复方案
问题分析
首次提交表单时错误信息不显示,核心原因有三点:
- React的
setErrors是异步状态更新,调用后不会立即同步更新errors变量,所以首次提交时console.log(errors)拿到的是更新前的旧值。 - 当前验证逻辑是逐个字段异步更新错误状态,且提交时直接执行回调函数,既没有等待验证完成,也没有判断验证是否通过。
- 缺少“验证通过时清除对应字段错误”的逻辑,比如之前字段有错误,再次提交时如果符合要求,错误不会被清除。
修复后的完整代码
import { useState } from 'react'; type Input = { [key: string]: string; }; type Error = { [key: string]: string | undefined; }; const useForm = (initValue: Input, callback: () => void) => { const [input, setInput] = useState(initValue); const [errors, setErrors] = useState<Error>({}); const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => { const { name, value } = e.target; clearValidation(name); setInput((prevState) => ({ ...prevState, [name]: value, })); }; const resetForm = () => { setInput(initValue); clearValidation(); }; const submit = (e: React.FormEvent<HTMLFormElement>) => { e.preventDefault(); // 1. 初始化空错误对象,清空旧错误 const newErrors: Error = {}; // 2. 批量验证所有字段,收集错误信息 Object.entries(input).forEach(([field, value]) => { const errorMsg = validator(field as keyof Error, value); if (errorMsg) { newErrors[field] = errorMsg; } }); // 3. 一次性更新错误状态 setErrors(newErrors); // 4. 仅当无错误时执行提交回调 if (Object.values(newErrors).every(msg => !msg)) { callback(); } }; // 修改validator为返回错误信息,不直接操作状态 const validator = (field: keyof Error, value: Input['key']): string | undefined => { switch (field) { case 'name': return value.length <= 2 ? 'Min 2 characters for name field' : undefined; case 'description': return value.length <= 2 ? 'Min 2 characters for description field' : undefined; default: return undefined; } }; const clearValidation = (field?: keyof Error) => { if (field) { setErrors((prevState) => ({ ...prevState, [field]: undefined, })); return; } setErrors({}); }; return { input, errors, setInput, handleChange, resetForm, submit }; }; export default useForm;
关键修改点说明
- 批量处理错误:在submit函数中先收集所有字段的错误信息,再一次性调用
setErrors,避免异步更新导致的状态不同步问题。 - 验证通过后执行回调:通过判断
newErrors是否为空,确保只有表单验证通过时才触发提交回调。 - 修复重置表单逻辑:将
setInput({})改为setInput(initValue),保证重置后回到初始状态。 - 调整validator职责:让validator只负责返回错误信息,状态更新逻辑统一放在submit中,代码更清晰可控。
- 完善清除验证逻辑:增加可选参数,支持清空单个或所有字段的错误。
内容的提问来源于stack exchange,提问作者qweezz
相关产品推荐
相关产品推荐

