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

使用shadcn封装的react-hook-form时useFormContext为null的问题

解决shadcn + react-hook-form中useFormContext为null的问题

问题复现

在项目中使用shadcn封装的react-hook-form时,多数场景正常,但某一特定组件运行时抛出useFormContext() is null错误,错误发生在useFormField函数的const { getFieldState, formState } = useFormContext();行。将该组件导入其他页面也会触发相同错误,但其他类似使用场景无异常。组件代码如下:

<Form {...form}>
  <FormField
    control={form.control}
    name={fieldName}
    render={({ field }) => (
      <FormItem>
        <FormControl>
          <Input type="number" {...field} />
        </FormControl>
        <FormMessage />
      </FormItem>
    )}
  />
</Form>

排查与解决方法

1. 确认Form组件的导入来源

确保你使用的Form组件是shadcn/ui提供的集成了react-hook-form上下文的版本,而非自定义或其他库的Form组件。正确导入路径示例:

import { Form } from '@/components/ui/form';

shadcn的Form组件内部封装了react-hook-form的FormProvider,只有通过它包裹的子组件才能获取到表单上下文。

2. 检查form实例的创建与传递

  • 确保form实例是通过react-hook-form的useForm()钩子正确创建的,且在组件渲染阶段同步生成:
    const form = useForm({
      defaultValues: {
        [fieldName]: 0, // 为目标字段设置合理默认值
      },
    });
    
  • 确认<Form {...form}>传递了完整的form实例属性,使用展开运算符通常可覆盖所有必要属性,无需手动拆分传递。

3. 确保FormField始终在Form上下文范围内

  • 检查是否存在条件渲染导致FormField在Form未渲染时提前渲染,比如:
    // 错误示例:FormField可能在isLoading为true时脱离Form上下文
    {isLoading ? <FormField ... /> : <Form {...form}><FormField ... /></Form>}
    
  • 若组件使用了React Portal,FormField被渲染到DOM的其他位置,会直接脱离Form的上下文范围,需调整组件结构避免这种情况。

4. 检查版本兼容性与依赖冲突

  • 当前使用的react-hook-form版本为7.54.2,React版本为19.0.0,确认shadcn/ui的版本是否适配这两个版本。部分旧版shadcn/ui可能对React 19或最新react-hook-form版本支持不足,建议升级shadcn/ui到最新稳定版。
  • 执行pnpm list react-hook-form查看项目中是否存在多个版本的react-hook-form,版本冲突会导致上下文无法共享。可通过package.json的resolutions字段统一版本:
    "pnpm": {
      "resolutions": {
        "react-hook-form": "7.54.2"
      }
    }
    

5. 排查组件嵌套与上下文污染

检查该特定组件是否被嵌套在另一个Form组件内部,多层Form嵌套可能导致上下文冲突或覆盖。若存在这种情况,需调整组件结构,确保每个FormField只属于一个Form上下文。

修正后的示例代码

import { useForm } from 'react-hook-form';
import { Form, FormField, FormItem, FormControl, FormMessage } from '@/components/ui/form';
import { Input } from '@/components/ui/input';

export function TargetFormComponent({ fieldName }) {
  // 正确创建form实例
  const form = useForm({
    defaultValues: {
      [fieldName]: 0,
    },
  });

  return (
    // 用shadcn的Form组件包裹所有表单字段
    <Form {...form}>
      <FormField
        control={form.control}
        name={fieldName}
        render={({ field }) => (
          <FormItem>
            <FormControl>
              <Input type="number" {...field} />
            </FormControl>
            <FormMessage />
          </FormItem>
        )}
      />
      <button type="submit">提交表单</button>
    </Form>
  );
}

内容的提问来源于stack exchange,提问作者Eino Gourdin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 06:08:11