如何实现Formik联动日期字段?存在问题寻求解决方案
解决Formik中日期字段联动及相关问题
核心问题分析
你当前的实现存在几个关键问题:
- 用
validate函数处理字段联动是错误的,validate仅用于字段校验,不应该用来修改其他字段值 - 用独立的
useState维护日期字符串,未与Formik表单状态同步,导致无法回填到对应字段 - 验证触发时机不符合预期,
validate的执行逻辑和字段变更时机不匹配
修改后的完整代码
import React from "react"; import { Formik, Form, Field, ErrorMessage } from "formik"; import * as Yup from "yup"; import CustomDatePicker from "./CustomDatePicker"; const CustomForm = () => { const initialValues = { fieldStart: new Date('07-01') || null, fieldEnd: new Date('06-30') || null }; const validationSchema = Yup.object({ fieldStart: Yup.date().required("Required").nullable(), fieldEnd: Yup.date().required("Required").nullable() }); const onSubmit = (values) => { console.log("submitted Form data", values); }; // 计算结束日期:开始日期减1天 const calculateEndDate = (startDate: Date | null): Date | null => { if (!startDate) return null; const endDate = new Date(startDate.getTime()); endDate.setDate(endDate.getDate() - 1); return endDate; }; // 计算开始日期:结束日期加1天 const calculateStartDate = (endDate: Date | null): Date | null => { if (!endDate) return null; const startDate = new Date(endDate.getTime()); startDate.setDate(startDate.getDate() + 1); return startDate; }; return ( <Formik initialValues={initialValues} validationSchema={validationSchema} onSubmit={onSubmit} > {(formik) => { return ( <Form> <div> <label htmlFor="fieldStart">Cycle Start </label> <Field name="fieldStart"> {({ form, field }) => { const { setFieldValue, validateField } = form; const handleStartChange = (val: Date | null) => { // 更新当前字段值 setFieldValue("fieldStart", val); // 计算并更新结束日期 const endVal = calculateEndDate(val); setFieldValue("fieldEnd", endVal); // 立即触发两个字段的验证 validateField("fieldStart"); validateField("fieldEnd"); }; return ( <CustomDatePicker format="dd/MM" id="fieldStart" name="fieldStart" {...field} onChange={handleStartChange} /> ); }} </Field> <ErrorMessage name="fieldStart" /> </div> <div> <label htmlFor="fieldEnd"> Cycle End </label> <Field name="fieldEnd"> {({ form, field }) => { const { setFieldValue, validateField } = form; const handleEndChange = (val: Date | null) => { // 更新当前字段值 setFieldValue("fieldEnd", val); // 计算并更新开始日期 const startVal = calculateStartDate(val); setFieldValue("fieldStart", startVal); // 立即触发两个字段的验证 validateField("fieldEnd"); validateField("fieldStart"); }; return ( <CustomDatePicker format="dd/MM" id="fieldEnd" name="fieldEnd" {...field} onChange={handleEndChange} /> ); }} </Field> <ErrorMessage name="fieldEnd" /> </div> <button type="submit" disabled={!formik.isValid}> Submit </button> </Form> ); }} </Formik> ); }; export default CustomForm;
问题逐一解决说明
字段回填与联动逻辑修正
移除独立的useState变量,直接通过Formik的setFieldValue同步表单状态,确保衍生日期能直接回填到目标字段;将联动计算逻辑移到字段的onChange事件中,这是处理字段联动的正确时机,而非依赖validate函数。首次变更验证触发问题
在onChange中手动调用validateField方法,更新字段值后立即触发对应字段的验证,解决首次变更不触发验证的问题。findDOMNode警告处理
该警告来自CustomDatePicker组件内部(大概率使用了Transition类组件),在React StrictMode下findDOMNode已被废弃。解决方法:- 若为自定义组件,给
Transition组件添加直接的ref引用,替换findDOMNode的使用 - 若为第三方日期选择器组件,升级到支持StrictMode的最新版本,或查看组件文档是否有禁用该警告的配置项
- 若为自定义组件,给
内容的提问来源于stack exchange,提问作者Steve
相关产品推荐
相关产品推荐

