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

如何实现Formik跳过与初始值相等字段的校验?

解决Formik不对与初始值相等的字段执行校验的问题

针对编辑表单场景(初始值为项目原有属性,新增校验规则不强制修改原有值),以下是两种可行方案:

方案一:Formik原生validate函数实现

放弃validationSchema,改用validate函数手动控制校验逻辑,仅当字段值与初始值不同时执行校验:

import React from "react";
import { Formik, Form, Field } from "formik";
import { TextField, Button } from "@mui/material";

const initialValues = {
  email: "existing-user@example.com"
};

// 单独定义邮箱校验规则,方便复用
const validateEmail = (value) => {
  if (!value) return "Email is required";
  if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) return "Invalid email format";
  return undefined;
};

export default function App() {
  return (
    <Formik
      initialValues={initialValues}
      validate={(values) => {
        const errors = {};
        // 仅当邮箱值与初始值不一致时,执行校验
        if (values.email !== initialValues.email) {
          const emailError = validateEmail(values.email);
          if (emailError) errors.email = emailError;
        }
        return errors;
      }}
      onSubmit={(values) => {
        alert(JSON.stringify(values, null, 2));
      }}
    >
      {({ errors, touched }) => (
        <Form>
          <Field
            as={TextField}
            name="email"
            label="Email"
            error={touched.email && Boolean(errors.email)}
            helperText={touched.email && errors.email}
            fullWidth
            margin="normal"
          />
          <Button type="submit" variant="contained" color="primary">
            Submit
          </Button>
        </Form>
      )}
    </Formik>
  );
}

该方案逻辑直观,后续新增字段时,只需在validate函数中添加对应字段的判断即可。

方案二:Yup条件校验实现

若希望保留Yup的Schema语法,可通过自定义校验规则,给字段添加"值不等于初始值时才校验"的条件:

import React from "react";
import { Formik, Form, Field } from "formik";
import { TextField, Button } from "@mui/material";
import * as Yup from "yup";

const initialValues = {
  email: "existing-user@example.com"
};

// 传入初始值生成校验Schema
const createValidationSchema = (initialVals) => {
  return Yup.object({
    email: Yup.string()
      // 未修改初始值则直接通过校验
      .test(
        "unmodified-field",
        "",
        (value) => value === initialVals.email
      )
      // 修改后执行完整邮箱校验,并抛出对应错误
      .transform(function (value) {
        if (value !== initialVals.email) {
          try {
            Yup.string()
              .email("Invalid email format")
              .required("Email is required")
              .validateSync(value);
          } catch (err) {
            this.createError({ message: err.message });
          }
        }
        return value;
      })
  });
};

export default function App() {
  const validationSchema = createValidationSchema(initialValues);

  return (
    <Formik
      initialValues={initialValues}
      validationSchema={validationSchema}
      onSubmit={(values) => {
        alert(JSON.stringify(values, null, 2));
      }}
    >
      {({ errors, touched }) => (
        <Form>
          <Field
            as={TextField}
            name="email"
            label="Email"
            error={touched.email && Boolean(errors.email)}
            helperText={touched.email && errors.email}
            fullWidth
            margin="normal"
          />
          <Button type="submit" variant="contained" color="primary">
            Submit
          </Button>
        </Form>
      )}
    </Formik>
  );
}

此方案保留了Yup的声明式语法,适合习惯用Yup管理校验规则的场景。

扩展提示(针对后续需求)

若后续需要将未修改但不符合新规则的字段转为警告(黄色提示),可在validate函数或Yup规则中添加自定义warnings对象,在UI层判断并渲染警告样式,不阻止表单提交。

内容的提问来源于stack exchange,提问作者Josh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 02:45:36