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

如何实现Formik字段输入时实时验证(避免全局触发问题)

实现Formik字段输入时实时验证

Formik默认只在表单提交或字段失焦时触发验证,现在要改成用户输入时就实时验证,但直接删掉touched.字段名的判断会导致所有字段同时显示错误。

解决思路

要搞定这个问题,核心是让Formik只在当前字段输入时验证该字段,同时保留touched状态控制错误显示,避免未交互的空字段提前弹出必填提示。下面是两种可行的实现方式:


方法1:利用Formik默认配置优化错误显示

Formik的useFormik默认就开了validateOnChange: true,会在字段变化时触发验证,但默认是验证整个表单。我们只需要调整错误显示逻辑,让它在用户开始输入当前字段或字段被触摸过时,才显示对应错误。

关键修改点

  • 确保每个字段都正确绑定{...getFieldProps("字段名")},它会自动处理onChange、onBlur事件,触发实时验证并更新touched状态
  • 错误显示逻辑改成:error={Boolean((touched.字段名 || formik.values.字段名) && errors.字段名)},这样用户一输入就触发验证,但没碰过的空字段不会提前显示必填错误

方法2:手动触发单个字段验证(精细控制)

如果需要更灵活的控制,可以在字段的onChange里手动调用formik.validateField("字段名"),只验证当前字段,避免全表单验证。


修改后的完整代码

import { Button, TextField } from "@mui/material";
import { useFormik } from "formik";
import * as Yup from "yup";
import { REGEX } from "../../../Constants/Regex/Regex";

const FormikPractice = () => {
  const { ONLY_NUMBER_THREE_DIGIT } = REGEX;

  const CustomerSchema = Yup.object().shape({
    parameter: Yup.string()
      .required("此字段为必填项")
      .matches(ONLY_NUMBER_THREE_DIGIT, "只能输入三位数字"),
    message: Yup.string()
      .required("此字段为必填项")
      .matches(ONLY_NUMBER_THREE_DIGIT, "只能输入三位数字"),
    blackList: Yup.string()
      .required("此字段为必填项")
      .matches(ONLY_NUMBER_THREE_DIGIT, "只能输入三位数字"),
    screen: Yup.string()
      .required("此字段为必填项")
      .matches(ONLY_NUMBER_THREE_DIGIT, "只能输入三位数字"),
  });

  const formik = useFormik({
    initialValues: {
      parameter: "",
      message: "",
      blackList: "",
      screen: "",
    },
    validationSchema: CustomerSchema,
    onSubmit: async (values) => console.log(values),
    // 显式声明开启输入时验证,默认就是true,写出来更直观
    validateOnChange: true,
  });

  const { errors, touched, handleSubmit, getFieldProps } = formik;

  return (
    <form
      style={{
        display: "grid",
        gridTemplateColumns: "repeat(2,1fr)",
        gap: "1rem",
        margin: "2rem",
      }}
      autoComplete="off"
      noValidate
      onSubmit={handleSubmit}
    >
      <TextField
        label="参数"
        name="parameter"
        id="parameter"
        inputProps={{ maxLength: 3 }}
        {...getFieldProps("parameter")}
        // 用户输入或字段被触摸时,显示错误
        error={Boolean((touched.parameter || formik.values.parameter) && errors.parameter)}
        helperText={(touched.parameter || formik.values.parameter) && errors.parameter}
      />
      <TextField
        label="消息"
        name="message"
        id="message"
        inputProps={{ maxLength: 3 }}
        {...getFieldProps("message")}
        error={Boolean((touched.message || formik.values.message) && errors.message)}
        helperText={(touched.message || formik.values.message) && errors.message}
      />
      <TextField
        label="黑名单"
        name="blackList"
        id="blackList"
        inputProps={{ maxLength: 3 }}
        {...getFieldProps("blackList")}
        error={Boolean((touched.blackList || formik.values.blackList) && errors.blackList)}
        helperText={(touched.blackList || formik.values.blackList) && errors.blackList}
      />
      <TextField
        label="屏幕"
        name="screen"
        id="screen"
        inputProps={{ maxLength: 3 }}
        {...getFieldProps("screen")}
        error={Boolean((touched.screen || formik.values.screen) && errors.screen)}
        helperText={(touched.screen || formik.values.screen) && errors.screen}
      />
      <Button sx={{ gridColumn: "1/-1" }} type="submit" variant="contained">
        提交
      </Button>
    </form>
  );
};

export default FormikPractice;

代码说明

  • 恢复了原代码中注释掉的{...getFieldProps("字段名")},确保Formik能正确跟踪字段的输入和触摸状态
  • 错误提示逻辑加入了formik.values.字段名判断,用户开始输入内容时(即使还没失焦)就会触发验证并显示错误,未交互的空字段不会提前弹出必填提示
  • 把原代码中的波斯语提示改成了中文,更易读

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 22:27:24