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
相关产品推荐
相关产品推荐

