You need to enable JavaScript to run this app. React结合Formik、Yup使用日历选择器时如何注册字段touched状态
优惠活动
大模型
产品
解决方案
定价
更多

React结合Formik、Yup使用日历选择器时如何注册字段touched状态

问题排查与修复

核心异常原因

  • 状态绑定错位:periodStart字段的error判断错误引用了touched.periodEnd的状态,状态关联和实际字段不匹配。
  • 缺少touched状态触发逻辑:MUI 日历选择器完成日期点选时,只会触发值更新的onChange事件,不会自动触发Formik绑定的blur逻辑,导致对应字段的touched状态始终为false,错误样式无法激活。
  • 提示逻辑不合理:helperText没有结合touched状态判断展示,会在用户未交互时就提前显示错误提示。

可直接复用的修复代码

import React, { FC, useRef } from "react";
import { Formik, Form, Field } from "formik";
import { KeyboardDatePicker } from "formik-material-ui-pickers";
import * as Yup from "yup";
import moment from "moment";
import { ReportConfig } from "../ReportConfig";

export type DProps = {
  type: Type | null,
  currentConfig: ReportConfig | null,
};

export const Dialog: FC<DProps> = ({ currentConfig }) => {
  const form: any = useRef(null);

  const initialValues = {
    periodStart: moment(currentConfig?.periodStart),
    periodEnd: moment(currentConfig?.periodEnd),
  };

  return (
    <Formik
      innerRef={form}
      initialValues={initialValues}
      validationSchema={Yup.object().shape({
        periodStart: Yup.date()
          .typeError("Enter a valid date.")
          .max(Yup.ref("periodEnd"), "Must be before End.")
          .required("Required"),
        periodEnd: Yup.date()
          .typeError("Enter a valid date.")
          .min(Yup.ref("periodStart"), "Must be after Start.")
          .required("Required"),
      })}
    >
      {({ values, errors, touched, setFieldTouched }) => (
        <Form>
          <Field
            variant="inline"
            autoOk
            name="periodStart"
            label="Start Date"
            inputVariant="outlined"
            component={KeyboardDatePicker}
            format="MM/DD/YYYY"
            // 日期选中后手动标记字段为已交互状态
            onChange={() => setFieldTouched("periodStart", true)}
            error={touched.periodStart && Boolean(errors.periodStart)}
            helperText={touched.periodStart ? errors.periodStart : ""}
          />
          <Field
            variant="inline"
            autoOk
            name="periodEnd"
            label="End Date"
            inputVariant="outlined"
            component={KeyboardDatePicker}
            format="MM/DD/YYYY"
            // 日期选中后手动标记字段为已交互状态
            onChange={() => setFieldTouched("periodEnd", true)}
            error={touched.periodEnd && Boolean(errors.periodEnd)}
            helperText={touched.periodEnd ? errors.periodEnd : ""}
          />
        </Form>
      )}
    </Formik>
  );
};

优化说明

  • 移除了手动传入的onBlur={handleBlur}逻辑,formik-material-ui-pickers组件已内置Formik的blur事件绑定,手动传入会造成事件触发时序异常。
  • 通过setFieldTouched在日期选中回调里同步更新交互状态,不管用户是手动输入日期还是通过日历点选日期,只要字段值触发校验规则,对应的错误样式就会正常激活。
  • 结合touched状态控制错误提示展示时机,避免初始页面加载时就铺满错误提示,影响使用体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.24 09:45:03