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

React中如何将作为children传入的输入框注册到useForm并取值

首先注意:所有需要注册的输入组件必须设置唯一的name属性,这是react-hook-form识别字段的必要前提。

方案1:遍历子元素注入注册属性(适合输入组件为MyForm直接子节点的简单场景)

你可以通过React.Children.map遍历传入的children,用React.cloneElement给符合条件的输入组件注入register返回的相关属性,全程用函数式组件实现,不需要类组件。
修改后的MyForm组件代码:

import React from 'react';
import { useForm, RegisterOptions } from 'react-hook-form';
import { TextField } from '@mui/material';

type MyFormProps = {
  children?: React.ReactNode
  // 可选:支持传入表单默认值等useForm配置
  defaultValues?: Record<string, any>
}

const MyForm: React.FC<MyFormProps > = (props) => {
  const { register, handleSubmit, formState: { errors } } = useForm({
    defaultValues: props.defaultValues
  });
  const onSubmit = handleSubmit(data => console.log(data));

  // 遍历处理子元素
  const processedChildren = React.Children.map(props.children, child => {
    // 只处理合法的React元素,且是TextField类型(可以根据你的需求扩展支持的组件类型)
    if (React.isValidElement(child) && child.type === TextField) {
      const inputName = child.props.name;
      // 没有name的输入组件不注册
      if (!inputName) return child;
      // 注入register返回的属性,同时保留原有属性
      return React.cloneElement(child, {
        ...register(inputName),
        // 可选:注入错误提示
        error: !!errors[inputName],
        helperText: errors[inputName]?.message as string
      });
    }
    // 非输入组件直接返回,比如你传入的Button
    return child;
  })

  return (
    <div>
      <form onSubmit={onSubmit}>
        {processedChildren}
      </form>
    </div>
  );
}

export default MyForm;

客户端App.tsx使用时只需给每个TextField加name属性即可:

import React from 'react';
import { TextField, Button } from '@mui/material';
import {MyForm} from 'react-myform';

function App() {
  return (
    <div>
      <MyForm defaultValues={{username: '', email: ''}}>
        <TextField name="username" label="用户名"/>
        <TextField name="email" label="邮箱"/>
        <Button type="submit" variant="contained">提交</Button>
      </MyForm>
    </div>
  );
}

export default App;

方案2:基于Context实现(适合输入组件嵌套在其他组件内的复杂场景)

如果你的输入组件不是MyForm的直接子节点,遍历children的方案会失效,此时可以用react-hook-form内置的Context能力实现,灵活度更高:
修改后的MyForm组件代码:

import React from 'react';
import { useForm, FormProvider } from 'react-hook-form';

type MyFormProps = {
  children?: React.ReactNode
  defaultValues?: Record<string, any>
  onSubmit?: (data: Record<string, any>) => void
}

const MyForm: React.FC<MyFormProps > = (props) => {
  const methods = useForm({
    defaultValues: props.defaultValues
  });
  const handleFormSubmit = methods.handleSubmit(data => {
    if (props.onSubmit) props.onSubmit(data);
    else console.log(data);
  });

  return (
    <div>
      <FormProvider {...methods}>
        <form onSubmit={handleFormSubmit}>
          {props.children}
        </form>
      </FormProvider>
    </div>
  );
}

export default MyForm;

你可以额外封装一个适配MUI TextField的表单项组件,方便用户直接使用:

// 你的node模块里的FormField组件
import React from 'react';
import { useFormContext, RegisterOptions } from 'react-hook-form';
import { TextField, TextFieldProps } from '@mui/material';

type FormFieldProps = TextFieldProps & {
  name: string
  rules?: RegisterOptions
}

export const FormField: React.FC<FormFieldProps> = ({name, rules, ...rest}) => {
  const { register, formState: { errors } } = useFormContext();
  return (
    <TextField
      {...rest}
      {...register(name, rules)}
      error={!!errors[name]}
      helperText={errors[name]?.message as string}
    />
  )
}

客户端使用示例:

import React from 'react';
import { Button } from '@mui/material';
import {MyForm, FormField} from 'react-myform';

function App() {
  return (
    <div>
      <MyForm 
        defaultValues={{username: '', email: ''}}
        onSubmit={(data) => console.log('提交数据:', data)}
      >
        {/* 哪怕嵌套在其他组件内也能正常工作 */}
        <div>
          <FormField name="username" label="用户名" rules={{required: '请输入用户名'}}/>
          <FormField name="email" label="邮箱" rules={{required: '请输入邮箱'}}/>
        </div>
        <Button type="submit" variant="contained">提交</Button>
      </MyForm>
    </div>
  );
}

export default App;

关于ref的疑问

不需要你自己单独维护ref实现注册,react-hook-form的register方法返回值已经包含了ref绑定逻辑,透传给输入组件后会自动完成关联,完全符合函数式组件的开发习惯。

内容的提问来源于stack exchange,提问作者Markus Profanter

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 06:27:03