You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现自定义可复用useForm钩子的提交验证并修复首次验证异常?

自定义useForm钩子验证逻辑修复方案

问题分析

首次提交表单时错误信息不显示,核心原因有三点:

  1. React的setErrors是异步状态更新,调用后不会立即同步更新errors变量,所以首次提交时console.log(errors)拿到的是更新前的旧值。
  2. 当前验证逻辑是逐个字段异步更新错误状态,且提交时直接执行回调函数,既没有等待验证完成,也没有判断验证是否通过。
  3. 缺少“验证通过时清除对应字段错误”的逻辑,比如之前字段有错误,再次提交时如果符合要求,错误不会被清除。

修复后的完整代码

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 19:36:18