React TypeScript中如何将useRef创建的Ref传递给子组件?
问题分析与解决方案
你的核心问题是forwardRef的泛型参数和回调函数参数使用错误,导致TypeScript类型不匹配。下面一步步拆解错误原因并给出正确实现:
错误根源
- 第一次定义组件时,
forwardRef<HTMLElement, React.HTMLProps<HTMLElement>>((ref) => { ... })的回调函数只写了ref参数,但forwardRef的回调函数实际接收两个参数:第一个是组件props,第二个是ref。TS把你写的ref参数识别成了props(类型是React.HTMLProps<HTMLElement>),再把这个props传给section的ref属性,自然会出现类型不兼容的错误。 - 后续修改时,你没有正确声明forwardRef的泛型,而是直接给ref参数硬套类型,导致父组件传递ref时类型冲突。
正确实现步骤
1. 子组件(Introduction)的正确写法
使用forwardRef时,严格遵循泛型参数顺序:
- 第一个泛型参数:ref要指向的DOM元素类型(这里是
HTMLElement,对应section标签) - 第二个泛型参数:组件的props类型(如果你的组件不需要自定义props,用
{}即可;如果需要透传section的原生属性,用React.HTMLAttributes<HTMLElement>)
代码示例:
import React, { forwardRef } from "react"; import myInfo from "../myInfo.json"; // 泛型第一个是ref类型,第二个是props类型 const Introduction = forwardRef<HTMLElement, React.HTMLAttributes<HTMLElement>>( (props, ref) => { // 把ref绑定到section,同时透传props(比如className、style等) return ( <section ref={ref} className="Introduction" {...props}> <p className="greeting">Welcome</p> <p className="intro">{myInfo.introduction}</p> <div className="picture"> {/* <PixelateToUnpixelate src={myInfo.myPicture} /> */} </div> </section> ); } ); export default Introduction;
2. 父组件中正确使用ref
父组件创建ref时,明确指定ref的类型为HTMLElement(和子组件的泛型对应),避免TS推断为null类型导致的冲突:
import { useRef, useEffect } from "react"; import Introduction from "./Introduction"; const ParentComponent = () => { // 明确ref的类型为HTMLElement | null const introRef = useRef<HTMLElement>(null); useEffect(() => { if (!introRef.current) return; // 初始化IntersectionObserver监听可见性 const observer = new IntersectionObserver( (entries) => { entries.forEach(entry => { if (entry.isIntersecting) { console.log("Introduction组件进入视口"); // 这里写你的逻辑,比如触发动画、统计曝光等 } else { console.log("Introduction组件离开视口"); } }); }, { threshold: 0.5 } // 自定义监听阈值 ); observer.observe(introRef.current); // 组件卸载时清理监听 return () => observer.disconnect(); }, []); return ( <div> <Introduction ref={introRef} /> </div> ); }; export default ParentComponent;
关键类型说明
forwardRef<T, P>:T是ref指向的DOM元素类型,P是组件的props类型。回调函数必须接收(props: P, ref: React.Ref<T>)两个参数。useRef<T>(initialValue):T是ref.current的类型,这里我们初始值是null,所以TS会自动推断current的类型为T | null,刚好和IntersectionObserver的要求匹配。- 避免使用
LegacyRef:这个类型是为了兼容React旧版的字符串ref,现代React推荐使用函数ref或ref对象,所以不需要手动指定LegacyRef。
内容的提问来源于stack exchange,提问作者CKang
相关产品推荐
相关产品推荐

