Next.js使用react-hook-form调用useForm时出现null属性读取报错
TypeError: Cannot read properties of null (reading 'useRef')
触发场景:Next.js + TypeScript + Sanity + TailwindCSS 技术栈下,引入
react-hook-form调用useForm时触发,错误定位在useForm<IFormInput>()调用行。
已尝试无效方案:
- 将Post组件改为箭头函数
- 将Post组件改为const声明形式
- 将IFormInput从interface改为type定义
这个报错和组件声明方式、TS类型定义完全无关,本质是react-hook-form内部调用React内置hookuseRef时,拿到的React上下文为null,90%以上是React多实例/版本不兼容、或Hook调用位置不符合规则导致的。
1. 优先修复React多实例/版本不匹配问题
这是该报错最高发的诱因:
- 先在项目根目录执行命令检查是否存在多版本React实例:
npm ls react npm ls react-dom
如果输出结果里出现多个不同版本号的react/react-dom,就会触发Hook调用上下文丢失的问题。
- 执行以下操作清理重装依赖:
# 删除依赖目录和锁文件,根据你用的包管理器选对应锁文件删除即可 rm -rf node_modules package-lock.json yarn.lock pnpm-lock.yaml # 重新安装依赖 npm install
- 确认版本兼容关系:React 18 对应使用
react-hook-form@7.x最新稳定版即可;如果是React 17及以下版本,要安装对应支持低版本React的react-hook-form版本,不要盲目装最新版。
2. 处理本地包链接导致的React实例冲突
如果你项目里用了npm link引用本地开发的其他包,会强制让webpack加载两份React,需要在next.config.js里加别名配置,强制全局使用项目根目录的React实例:
/** @type {import('next').NextConfig} */ const nextConfig = { webpack: (config) => { config.resolve.alias = { ...config.resolve.alias, react: require.resolve('react'), 'react-dom': require.resolve('react-dom') } return config } } module.exports = nextConfig
3. 确认组件调用位置符合Hook规则
从你贴的代码看,useForm是在Post组件顶层调用的,没有放在条件判断、循环、子函数内部,这部分写法符合要求,不需要调整。
注:你之前尝试的几个修改方向完全不影响运行时逻辑:TS的interface/type在编译阶段会被完全擦除,组件的声明方式(function/const箭头函数)只要是合法的函数式组件都不会导致Hook调用失败,不需要在这几个点浪费时间。
4. 重启服务验证
修改完配置、重装依赖后,一定要停止当前的next dev进程重新启动,再清空浏览器缓存硬刷新页面验证。
内容的提问来源于stack exchange,提问作者Aidan Mc Intosh

