React 强大的表单验证库formik之集成Yup、React Hook Form库

发布于:2025-07-04 ⋅ 阅读:(19) ⋅ 点赞:(0)

简介

Formik 是为 React 开发的开源表单库,提供状态管理、验证和提交处理功能,可简化复杂表单的开发。

核心优势

‌- 状态管理 ‌:自动跟踪输入值、验证状态和提交进度,无需手动编写状态逻辑。 ‌
‌- 验证功能 ‌:支持声明式验证规则(如字段类型、长度限制、异步验证),实时反馈错误信息。 ‌
‌- 集成能力 ‌:可与 Yup (验证)、 React Hook Form (表单钩子)等库组合使用,扩展功能。

安装

npm install formik

示例

基本用法

import { useFormik } from "formik";

export default function Formik() {
  const formik = useFormik({
    initialValues: {
      username: "",
      email: "",
    },
    validate: (values) => {
      const errors = {};
      if (!values.username) {
        errors.username = "用户名是必填项";
      } else if (values.username.length < 2) {
        errors.username = "用户名至少2个字符";
      }
      if (!values.email) {
        errors.email = "邮箱是必填项";
      } else if (
        !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)
      ) {
        errors.email = "无效的邮箱地址";
      }
      return errors;
    },
    onSubmit: (values) => {
      console.log(values);
      alert(JSON.stringify(values, null, 2));
    },
  });

  return (
    <form
      onSubmit={formik.handleSubmit}
      className="max-w-sm mx-auto mt-10 p-6 border rounded shadow"
    >
      <div className="mb-4">
        <label htmlFor="username" className="block mb-1 font-bold">
          用户名
        </label>
        <input
          id="username"
          name="username"
          type="text"
          onChange={formik.handleChange}
          onBlur={formik.handleBlur}
          value={formik.values.username}
          className="w-full px-3 py-2 border rounded"
        />
        {formik.touched.username && formik.errors.username ? (
          <div className="text-red-500 text-sm mt-1">
            {formik.errors.username}
          </div>
        ) : null}
      </div>
      <div className="mb-4">
        <label htmlFor="email" className="block mb-1 font-bold">
          邮箱
        </label>
        <input
          id="email"
          name="email"
          type="email"
          onChange={formik.handleChange}
          onBlur={formik.handleBlur}
          value={formik.values.email}
          className="w-full px-3 py-2 border rounded"
        />
        {formik.touched.email && formik.errors.email ? (
          <div className="text-red-500 text-sm mt-1">{formik.errors.email}</div>
        ) : null}
      </div>
      <button
        type="submit"
        className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
      >
        提交
      </button>
    </form>
  );
}

集成 yup

import { useFormik } from "formik";
import * as Yup from "yup";

export default function Formik() {
  const formik = useFormik({
    initialValues: {
      username: "",
      email: "",
    },
    validationSchema: Yup.object({
      username: Yup.string()
        .min(2, "用户名至少2个字符")
        .required("用户名是必填项"),
      email: Yup.string().email("无效的邮箱地址").required("邮箱是必填项"),
    }),
    onSubmit: (values) => {
      alert(JSON.stringify(values, null, 2));
    },
  });

  return (
    <form
      onSubmit={formik.handleSubmit}
      className="max-w-sm mx-auto mt-10 p-6 border rounded shadow"
    >
      <div className="mb-4">
        <label htmlFor="username" className="block mb-1 font-bold">
          用户名
        </label>
        <input
          id="username"
          name="username"
          type="text"
          onChange={formik.handleChange}
          onBlur={formik.handleBlur}
          value={formik.values.username}
          className="w-full px-3 py-2 border rounded"
        />
        {formik.touched.username && formik.errors.username ? (
          <div className="text-red-500 text-sm mt-1">
            {formik.errors.username}
          </div>
        ) : null}
      </div>
      <div className="mb-4">
        <label htmlFor="email" className="block mb-1 font-bold">
          邮箱
        </label>
        <input
          id="email"
          name="email"
          type="email"
          onChange={formik.handleChange}
          onBlur={formik.handleBlur}
          value={formik.values.email}
          className="w-full px-3 py-2 border rounded"
        />
        {formik.touched.email && formik.errors.email ? (
          <div className="text-red-500 text-sm mt-1">{formik.errors.email}</div>
        ) : null}
      </div>
      <button
        type="submit"
        className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
      >
        提交
      </button>
    </form>
  );
}

集成 react-hook-form

import { useForm } from "react-hook-form";

export default function Formik() {
  const {
    register,
    handleSubmit,
    formState: { errors, touchedFields },
  } = useForm({
    mode: "onChange",
    defaultValues: {
      username: "",
      email: "",
    },
  });

  const onSubmit = (values) => {
    console.log(values);
    alert(JSON.stringify(values, null, 2));
  };

  return (
    <form
      onSubmit={handleSubmit(onSubmit)}
      className="max-w-sm mx-auto mt-10 p-6 border rounded shadow"
    >
      <div className="mb-4">
        <label htmlFor="username" className="block mb-1 font-bold">
          用户名
        </label>
        <input
          id="username"
          {...register("username", {
            required: "用户名是必填项",
            minLength: { value: 2, message: "用户名至少2个字符" },
          })}
          className="w-full px-3 py-2 border rounded"
        />
        {touchedFields.username && errors.username && (
          <div className="text-red-500 text-sm mt-1">
            {errors.username.message}
          </div>
        )}
      </div>
      <div className="mb-4">
        <label htmlFor="email" className="block mb-1 font-bold">
          邮箱
        </label>
        <input
          id="email"
          type="email"
          {...register("email", {
            required: "邮箱是必填项",
            pattern: {
              value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
              message: "无效的邮箱地址",
            },
          })}
          className="w-full px-3 py-2 border rounded"
        />
        {touchedFields.email && errors.email && (
          <div className="text-red-500 text-sm mt-1">
            {errors.email.message}
          </div>
        )}
      </div>
      <button
        type="submit"
        className="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600"
      >
        提交
      </button>
    </form>
  );
}

formik validate、yup、react-hook-form 集成对比

1. Formik 自带 validate

  • 写法:在 useFormik 里传入 validate 函数,手动校验每个字段,返回错误对象。
  • 优点
  • 灵活,适合简单或自定义复杂逻辑。
  • 不依赖第三方库。
  • 缺点
  • 代码冗长,重复性高。
  • 维护性较差,规则多时易出错。
  • 示例
  validate: (values) => {
    const errors = {};
    if (!values.username) {
      errors.username = "用户名是必填项";
    } else if (values.username.length < 2) {
      errors.username = "用户名至少2个字符";
    }
    // ... 其他校验
    return errors;
  };

2. Formik 集成 Yup

  • 写法:传入 validationSchema,使用 Yup 对象声明式定义规则。
  • 优点
  • 规则声明式,简洁易读。
  • 支持复杂嵌套、异步校验、类型校验等。
  • 维护性好,易扩展。
  • 缺点
  • 需额外安装 Yup。
  • 某些极端自定义逻辑需配合 validate。
  • 示例
  validationSchema: Yup.object({
    username: Yup.string()
      .min(2, "用户名至少2个字符")
      .required("用户名是必填项"),
    email: Yup.string().email("无效的邮箱地址").required("邮箱是必填项"),
  });

3. React Hook Form

  • 写法:通过 register 注册字段时直接传入校验规则,也可结合 Yup。
  • 优点
  • 语法简洁,性能优异(按需渲染)。
  • 支持原生表单校验、异步校验。
  • 易与 Yup 等 schema 库集成。
  • 缺点
  • 语法与 Formik 不同,迁移需适应。
  • 复杂表单时需结合第三方库。
  • 示例
  {...register("username", {
    required: "用户名是必填项",
    minLength: { value: 2, message: "用户名至少2个字符" },
  })}

总结对比表

特性 Formik validate Formik + Yup React Hook Form
书写方式 手写函数 声明式 schema 注册时传规则
依赖 Yup 无/可选 Yup
代码量
维护性 一般
灵活性
性能 一般 一般
适合场景 简单/自定义复杂逻辑 规则多/复杂表单 性能敏感/大表单

结论

  • 简单表单可用 Formik 的 validate,复杂表单推荐 Yup 或 React Hook Form。
  • 追求声明式、可维护性优先用 Yup。
  • 性能和体验优先可选 React Hook Form。

 React 强大的表单验证库formik之集成Yup、React Hook Form库 - 高质量源码分享平台-免费下载各类网站源码与模板及前沿动态资讯


网站公告

今日签到

点亮在社区的每一天
去签到