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

如何在Formik父组件中获取子组件错误对象以标记校验区域?

实现父组件获取Formik表单错误对象的方案

方法一:通过回调函数实时同步错误对象

这种方式可以在表单错误变化时(输入校验、提交校验)实时将错误传递给父组件,适合实时标记未校验区域。

1. 父组件修改

添加状态存储错误对象,并定义接收错误的回调函数:

import { useState } from 'react';

// ...父组件其他逻辑
const [formErrors, setFormErrors] = useState({});

// 接收子组件传递的错误对象
const handleFormErrors = (errors) => {
  setFormErrors(errors);
};

将回调函数传递给FormContainer组件:

<FormContainer
  initialFieldValues={id != undefined ? cvRecord : cvFormFields}
  formData={getFieldsByCategory(cvFormFields, selectOption.type)}
  formValidation={cvFormFields}
  onFormSubmit={onFormSubmit}
  onErrorsChange={handleFormErrors} {/* 新增回调props */}
>
  {/* 按钮组 */}
  <div className="text-md-end mt-5">
    <button className="btn btn-primary ms-2 mb-2" type="submit">
      Save <i className="bi bi-file-earmark-fill" />
    </button>
    <button
      type="button"
      className="btn btn-danger ms-2 mb-2"
      data-bs-toggle="modal"
      data-bs-target="#cvdownloadmodal"
    >
      <i className="bi bi-eye me-1" />
      Preview and Download
    </button>
  </div>
</FormContainer>

之后就可以用formErrors标记对应区域,比如给未填写字段所在区域添加红色边框:

// 示例:假设某个区域对应字段`workExperience`
<div className={`section-container ${formErrors.workExperience ? 'error-highlight' : ''}`}>
  {/* 该区域的表单内容 */}
</div>

添加CSS样式:

.error-highlight {
  border: 1px solid #dc3545;
  padding: 1rem;
  border-radius: 0.375rem;
}

2. 子组件FormContainer修改

新增接收onErrorsChange回调的props,并监听Formik的错误变化:

import { Form, Formik, useEffect } from "formik";
import React from "react";
import GenerateFields from "./GenerateFields";
import { getFormInitialValue, getFormValidations } from "./utility/formUtils";
import * as Yup from "yup";
import { toast } from "react-toastify";

const FormContainer = ({
  initialFieldValues = [],
  formData = [],
  onFormSubmit = "",
  formValidation = [],
  extraInputClass = "",
  children,
  onErrorsChange, {/* 新增接收回调 */}
  ...otherProps
}) => {
  const withValidation = formValidation ? true : false;

  const initialValues = Array.isArray(initialFieldValues)
    ? getFormInitialValue(initialFieldValues)
    : initialFieldValues;

  const validationSchema = Yup.object().shape(
    getFormValidations(formValidation)
  );

  return (
    <Formik
      initialValues={initialValues}
      validationSchema={withValidation ? validationSchema : ""}
      onSubmit={
        onFormSubmit
          ? (val, { errors }) => {
              // 提交时传递错误
              if (onErrorsChange) onErrorsChange(errors);
              onFormSubmit(val, { errors });
            }
          : (val, { errors }) => {
              console.log("🚀 ~ file: FormContainer.jsx:38 ~ val", errors);
              if (onErrorsChange) onErrorsChange(errors);
              // 原有setFormValues逻辑
            }
      }
      enableReinitialize={true}
    >
      {(formAttributes) => {
        // 实时监听错误变化并传递给父组件
        useEffect(() => {
          if (onErrorsChange) {
            onErrorsChange(formAttributes.errors);
          }
        }, [formAttributes.errors, onErrorsChange]);

        return (
          <Form className="formikContainer row m-2">
            {formData.map((fieldAttribute, index) => {
              return (
                <GenerateFields
                  key={index}
                  inputAttributes={fieldAttribute}
                  formActions={formAttributes}
                  withValidation={withValidation}
                />
              );
            })}
            {children && children}
          </Form>
        );
      }}
    </Formik>
  );
};

export default FormContainer;

方法二:通过Ref暴露错误获取方法

如果只需要在特定时机(比如点击预览按钮时)获取错误,可使用useImperativeHandle暴露获取错误的方法。

1. 父组件修改

创建Ref并绑定到FormContainer,在需要时调用获取错误的方法:

import { useRef, useState } from 'react';

const formContainerRef = useRef(null);
const [formErrors, setFormErrors] = useState({});

// 比如点击预览按钮时获取错误
const handlePreview = () => {
  const errors = formContainerRef.current?.getErrors();
  setFormErrors(errors);
  // 后续处理预览逻辑
};

// 修改预览按钮的点击事件
<button
  type="button"
  className="btn btn-danger ms-2 mb-2"
  data-bs-toggle="modal"
  data-bs-target="#cvdownloadmodal"
  onClick={handlePreview}
>
  <i className="bi bi-eye me-1" />
  Preview and Download
</button>

// 绑定Ref到FormContainer
<FormContainer
  ref={formContainerRef}
  initialFieldValues={id != undefined ? cvRecord : cvFormFields}
  formData={getFieldsByCategory(cvFormFields, selectOption.type)}
  formValidation={cvFormFields}
  onFormSubmit={onFormSubmit}
>
  {/* 按钮组 */}
</FormContainer>

2. 子组件FormContainer修改

使用forwardRef和useImperativeHandle暴露获取错误的方法:

import { Form, Formik, useFormikContext, useImperativeHandle, forwardRef } from "formik";
import React from "react";
import GenerateFields from "./GenerateFields";
import { getFormInitialValue, getFormValidations } from "./utility/formUtils";
import * as Yup from "yup";
import { toast } from "react-toastify";

// 用forwardRef包裹组件
const FormContainer = forwardRef(({
  initialFieldValues = [],
  formData = [],
  onFormSubmit = "",
  formValidation = [],
  extraInputClass = "",
  children,
  ...otherProps
}, ref) => {
  const withValidation = formValidation ? true : false;

  const initialValues = Array.isArray(initialFieldValues)
    ? getFormInitialValue(initialFieldValues)
    : initialFieldValues;

  const validationSchema = Yup.object().shape(
    getFormValidations(formValidation)
  );

  // 获取Formik上下文
  const formikCtx = useFormikContext();

  // 暴露getErrors方法给父组件
  useImperativeHandle(ref, () => ({
    getErrors: () => formikCtx.errors
  }));

  return (
    <Formik
      initialValues={initialValues}
      validationSchema={withValidation ? validationSchema : ""}
      onSubmit={onFormSubmit ? onFormSubmit : (val, { errors }) => {
          console.log("🚀 ~ file: FormContainer.jsx:38 ~ val", errors);
          // 原有setFormValues逻辑
        }}
      enableReinitialize={true}
    >
      {(formAttributes) => (
        <Form className="formikContainer row m-2">
          {formData.map((fieldAttribute, index) => {
            return (
              <GenerateFields
                key={index}
                inputAttributes={fieldAttribute}
                formActions={formAttributes}
                withValidation={withValidation}
              />
            );
          })}
          {children && children}
        </Form>
      )}
    </Formik>
  );
});

export default FormContainer;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 05:35:27