React中useRef与forwardRef结合使用的正确方法及TS报错解决
错误原因
- 你没有为
React.forwardRef指定泛型参数,TS默认推导转发的ref类型为unknown,和你内部声明的HTMLDivElement类型ref不匹配,这是类型报错的直接诱因。 - 转发的ref存在两种合法形式:
RefObject对象、回调函数,你直接用ref || innerRef的写法只兼容了对象形式的ref,没有覆盖回调ref的场景,逻辑本身存在缺陷。
修复方案
你可以通过回调ref的形式同时为内部ref和转发ref赋值,完全覆盖所有场景,也不会有类型问题:
- 首先修改
App.tsx,给内部ref指定正确的类型:
import { useRef } from "react"; import Child from "./Child"; export default function App() { // 明确ref指向的是HTMLDivElement类型 const ref = useRef<HTMLDivElement>(null); console.log("App ref: ", ref); return ( <div className="App"> <Child ref={ref} /> </div> ); }
- 再修改
Child.tsx,补全forwardRef泛型,用回调ref同步两个ref的值:
import React, { useEffect, useRef } from "react"; // 第一个泛型指定ref暴露的类型为HTMLDivElement,第二个泛型指定组件props类型 export default React.forwardRef<HTMLDivElement, Record<string, never>>((props, ref) => { const innerRef = useRef<HTMLDivElement>(null); useEffect(() => { // 内部直接使用innerRef即可 if (innerRef.current) { console.log("clientWidth: ", innerRef.current.clientWidth); // 执行你需要的DOM操作 } }, []); return ( <div ref={(node) => { // 同步DOM节点到内部ref innerRef.current = node; // 同步DOM节点到父组件转发的ref if (typeof ref === "function") { ref(node); } else if (ref) { ref.current = node; } }} ></div> ); });
方案说明
- 所有类型完全匹配,不会再触发TS报错
- 同时兼容了对象形式、回调形式的转发ref,覆盖所有合法使用场景
- 内部逻辑直接使用
innerRef即可,不需要额外处理转发ref的类型差异 - 父组件可以正常拿到子组件内部的div DOM元素,符合预期功能
内容的提问来源于stack exchange,提问作者Lin Du
相关产品推荐
相关产品推荐

