React Hook Form传递control给嵌套表单时崩溃问题求助
问题:React Hook Form嵌套子表单复用自定义输入组件时出现
control._names未定义错误 我需要编写一个基于MUI的子表单组件,对应包含少量字段的MoneyT数据类型,嵌套在父表单组件中。父表单通过useForm<ExpenseT>({ ... })创建control对象,ExpenseT类型的字段中包含一个MoneyT类型的对象,并将control传递给子组件。
当直接在Controller的render函数中使用MUI的<TextField />构建子组件时,一切正常。但当使用接收control参数的自定义组件TextFormInput构建子组件时,启动时会崩溃,报错:Uncaught TypeError: control._names is undefined
正常场景中,control._names包含父类型所有字段的相关数据,看起来control在经过中间组件层传递时丢失了某些上下文,希望了解需要修改什么才能在MoneyForm中复用TextFormInput组件。
父与子类型
type ExpenseT = { purpose: string; amount: MoneyT; } type MoneyT = { magnitude: number; currency: string; }
父表单组件
const ExpenseForm = (): ReactElement => { const { control, handleSubmit } = useForm<ExpenseT>({ defaultValues: defaultExpense }); const onSubmit = (data: ExpenseT) => { console.log(`Expense of ${data.amount.magnitude} ${data.amount.currency} for ${data.purpose}`); } return ( ... 布局代码省略 ... <Stack spacing={4}> <TextFormInput control={control} fieldName="purpose" label="Purpose" /> <MoneyForm control={control} label="How Much Dash?" fieldName="amount" /> <Button onClick={handleSubmit(onSubmit)}>SAVE</Button> </Stack> ); }
子表单组件 - 正常工作版本
const MoneyForm = ({control, fieldName, label}: FormInputPropsT ): ReactElement => ( <Stack> <Divider/> <Typography variant="subtitle1">{label}</Typography> <Grid container direction="row" columnSpacing={2}> <Grid item xs={8}> <Controller name={`${fieldName}.magnitude`} control={control} render={({ field: { onChange, value }, fieldState: { error }, }) => ( <TextField helperText={error ? error.message : null} error={!!error} onChange={onChange} value={value} fullWidth label="Amount" variant="outlined" /> )} /> </Grid> <Grid item xs={4}> <Controller name={`${fieldName}.currency`} control={control} render={({ field: { onChange, value }, fieldState: { error }, }) => ( <TextField helperText={error ? error.message : null} error={!!error} onChange={onChange} value={value} fullWidth label="Currency" variant="outlined" /> )}/> </Grid> </Grid> </Stack> );
子表单组件 - 异常版本(触发报错)
const MoneyForm = ({control, fieldName, label}: FormInputPropsT ): ReactElement => ( <Box> <Stack> <Divider/> <Typography variant="subtitle1">{label}</Typography> <Grid container direction="row" columnSpacing={2}> <Grid item xs={8}> <TextFormInput control={{control}} fieldName={`${fieldName}.magnitude`} label="Amount" /> </Grid> <Grid item xs={4}> <TextFormInput control={{control}} fieldName={`${fieldName}.currency`} label="Currency" /> </Grid> </Grid> </Stack> </Box> );
解决方案
问题根源是异常版本中传递control的方式错误:你把原control对象包裹在了一个新对象{control}中传递,导致TextFormInput拿到的不是React Hook Form原生的control实例,而是一个嵌套了一层的对象,自然找不到_names属性。
只需要去掉多余的对象包装,直接传递原control实例即可:
const MoneyForm = ({control, fieldName, label}: FormInputPropsT ): ReactElement => ( <Box> <Stack> <Divider/> <Typography variant="subtitle1">{label}</Typography> <Grid container direction="row" columnSpacing={2}> <Grid item xs={8}> <TextFormInput control={control} fieldName={`${fieldName}.magnitude`} label="Amount" /> </Grid> <Grid item xs={4}> <TextFormInput control={control} fieldName={`${fieldName}.currency`} label="Currency" /> </Grid> </Grid> </Stack> </Box> );
修改后,TextFormInput就能获取到正确的control实例,正常访问其内部属性,不会再触发报错。
内容的提问来源于stack exchange,提问作者onouv
相关产品推荐
相关产品推荐

