如何在 React 中实现一个可复用的自定义 Hook 来管理表单状态和验证?

如何在 React 中实现一个可复用的自定义 Hook 来管理表单状态和验证?

回答与解析:
可以通过创建一个名为 useFormControl 的自定义 Hook 来集中处理表单字段的状态、输入变更、以及基本验证逻辑。以下是一个典型实现:

import { useState, useCallback } from 'react';

function useFormControl(initialValues, validationRules) {
  const [values, setValues] = useState(initialValues);
  const [errors, setErrors] = useState({});

  const handleChange = useCallback((name, value) => {
    setValues(prev => ({ ...prev, [name]: value }));
    // 清除对应字段的错误(可选)
    if (errors[name]) {
      setErrors(prev => ({ ...prev, [name]: '' }));
    }
  }, [errors]);

  const validate = useCallback(() => {
    const newErrors = {};
    for (const field in validationRules) {
      const rule = validationRules[field];
      if (rule.required && !values[field]) {
        newErrors[field] = `${field} is required`;
      } else if (rule.pattern && !rule.pattern.test(values[field])) {
        newErrors[field] = rule.message || `Invalid ${field}`;
      }
    }
    setErrors(newErrors);
    return Object.keys(newErrors).length === 0;
  }, [values, validationRules]);

  const reset = useCallback(() => {
    setValues(initialValues);
    setErrors({});
  }, [initialValues]);

  return { values, errors, handleChange, validate, reset };
}

使用示例:

function LoginForm() {
  const { values, errors, handleChange, validate } = useFormControl(
    { email: '', password: '' },
    {
      email: { required: true, pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, message: '请输入有效邮箱' },
      password: { required: true }
    }
  );

  const handleSubmit = (e) => {
    e.preventDefault();
    if (validate()) {
      console.log('提交数据:', values);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        value={values.email}
        onChange={(e) => handleChange('email', e.target.value)}
        placeholder="邮箱"
      />
      {errors.email && <span style={{ color: 'red' }}>{errors.email}</span>}

      <input
        type="password"
        value={values.password}
        onChange={(e) => handleChange('password', e.target.value)}
        placeholder="密码"
      />
      {errors.password && <span style={{ color: 'red' }}>{errors.password}</span>}

      <button type="submit">登录</button>
    </form>
  );
}

解析:

  • 自定义 Hook 将表单状态(values)、错误信息(errors)、变更处理(handleChange)、验证(validate)和重置(reset)封装在一起,提升复用性。
  • 使用 useCallback 优化性能,避免每次渲染都生成新函数。
  • 验证规则通过对象传入,支持 required 和正则 pattern 等常见规则,易于扩展。
  • 该模式适用于中小型表单,复杂场景可考虑 Formik 或 React Hook Form 等成熟库。

发表评论 (审核通过后显示评论):

昵称:
邮箱:
内容: