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

React Hook Form提交表单仅返回合成事件,无法获取表单数据

问题原因分析

你当前的核心问题是弹窗确认按钮与表单提交逻辑脱节:
你给ConfirmationDialog的onConfirm直接绑定了handleConfirmAddScreen,但弹窗按钮的点击事件并没有触发表单的submit流程——此时传入函数的是按钮的合成事件对象,而非react-hook-form处理后的表单数据。

两种可行解决方案

方案一:让弹窗确认按钮触发表单提交(推荐,适配表单校验)

这个方案会复用react-hook-form的内置校验逻辑,只有表单校验通过后才会提交数据,更符合表单设计规范。

步骤1:改造AddScreen组件,暴露手动提交方法

用forwardRef和useImperativeHandle把表单的提交方法暴露给父组件:

import { forwardRef, useRef, useImperativeHandle } from 'react';
import { useForm, FormProvider } from 'react-hook-form';
import { Stack, TextField, MenuItem } from '@mui/material';

export const AddScreen = forwardRef(({ onSubmit }, ref) => {
  const formRef = useRef(null);
  const formProps = useForm({ mode: "onChange" });
  const { handleSubmit, register, watch } = formProps;

  // 暴露给父组件的手动提交方法
  useImperativeHandle(ref, () => ({
    triggerSubmit: () => {
      formRef.current?.dispatchEvent(new Event('submit', { bubbles: true }));
    }
  }));

  return (
    <FormProvider {...formProps}>
      <form ref={formRef} onSubmit={handleSubmit((data) => {
        onSubmit(data);
      })}>
        <Stack direction="column" gap="2rem">
          <TextField
            label="Screen Name"
            required
            select
            name="screenName"
            fullWidth
            value={watch("screenName")}
            variant="outlined"
            {...register("screenName", { required: "This field is required." })}
            margin="dense"
          >
            {screenNames?.map((item, index) => (
              <MenuItem key={index} value={item.value}>
                {item.label}
              </MenuItem>
            ))}
          </TextField>
        </Stack>
      </form>
    </FormProvider>
  );
});

AddScreen.displayName = 'AddScreen';

步骤2:修改Managerole组件,调用子组件的提交方法

给AddScreen绑定ref,弹窗确认时调用子组件暴露的triggerSubmit方法:

import { useRef, useState } from 'react';
import { ConfirmationDialog } from './你的弹窗组件路径';
import { AddScreen } from './AddScreen';

const Managerole = () => {
  const [isAddScreenDialogOpen, setIsAddScreenDialogOpen] = useState(false);
  const addScreenRef = useRef(null);

  const handleConfirmAddScreen = (data) => {
    console.log('表单数据:', data); // 现在能正常拿到表单值
    setIsAddScreenDialogOpen(false);
  };

  return (
    <>
      {/* 其他业务代码,比如打开弹窗的按钮 */}
      <ConfirmationDialog
        isOpen={isAddScreenDialogOpen}
        title="Add Screen"
        content={<AddScreen ref={addScreenRef} onSubmit={handleConfirmAddScreen} />}
        onClose={() => setIsAddScreenDialogOpen(false)}
        cancelBtnText="Cancel"
        confirmBtnText="Save"
        onConfirm={() => {
          // 调用子组件的提交方法,触发表单校验与提交
          addScreenRef.current?.triggerSubmit();
        }}
      />
    </>
  );
};

export default Managerole;

方案二:实时同步表单数据到父组件

如果不需要严格的表单校验,或者想自己控制校验逻辑,可以实时把表单数据同步到父组件,弹窗确认时直接使用:

步骤1:改造AddScreen组件,实时传递表单数据

import { useEffect } from 'react';
import { useForm, FormProvider } from 'react-hook-form';
import { Stack, TextField, MenuItem } from '@mui/material';

export const AddScreen = ({ onFormChange }) => {
  const formProps = useForm({ mode: "onChange" });
  const { register, watch, getValues } = formProps;

  // 实时把表单数据传给父组件
  useEffect(() => {
    onFormChange(getValues());
  }, [getValues, onFormChange]);

  return (
    <FormProvider {...formProps}>
      <form>
        <Stack direction="column" gap="2rem">
          <TextField
            label="Screen Name"
            required
            select
            name="screenName"
            fullWidth
            value={watch("screenName")}
            variant="outlined"
            {...register("screenName", { required: "This field is required." })}
            margin="dense"
          >
            {screenNames?.map((item, index) => (
              <MenuItem key={index} value={item.value}>
                {item.label}
              </MenuItem>
            ))}
          </TextField>
        </Stack>
      </form>
    </FormProvider>
  );
};

步骤2:修改Managerole组件,接收并使用表单数据

import { useState } from 'react';
import { ConfirmationDialog } from './你的弹窗组件路径';
import { AddScreen } from './AddScreen';

const Managerole = () => {
  const [isAddScreenDialogOpen, setIsAddScreenDialogOpen] = useState(false);
  const [formData, setFormData] = useState({});

  const handleConfirmAddScreen = () => {
    console.log('表单数据:', formData); // 拿到实时同步的表单值
    setIsAddScreenDialogOpen(false);
  };

  return (
    <>
      {/* 其他业务代码 */}
      <ConfirmationDialog
        isOpen={isAddScreenDialogOpen}
        title="Add Screen"
        content={<AddScreen onFormChange={setFormData} />}
        onClose={() => setIsAddScreenDialogOpen(false)}
        cancelBtnText="Cancel"
        confirmBtnText="Save"
        onConfirm={handleConfirmAddScreen}
      />
    </>
  );
};

export default Managerole;
注意事项
  • 方案一优先:会自动触发react-hook-form的校验规则,只有校验通过才会执行handleConfirmAddScreen,适合需要校验的场景
  • 方案二适合简单场景:但需要自行处理校验逻辑,避免用户提交不合法的数据

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 02:06:01