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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 07:09:51