React+TypeScript:如何在子组件中使用forwardRef传递的引用数据
问题解答
1. 先明确:用forwardRef传递非DOM/组件实例的数据,并不推荐
React官方虽然提到useRef可以存储不触发渲染的数据,但forwardRef的设计初衷是传递DOM元素或自定义组件的引用,而非普通数据。用它来传数据会违背React的语义,还会带来类型处理的麻烦(比如你遇到的Ref<T>包含函数式ref和对象式ref的混合类型问题),属于非常规用法,不建议这么做。
2. 更合适的替代方案:用普通props传递ref对象
直接把useRef创建的对象作为普通props传给子组件,类型清晰,也符合React的常规用法:
import { useRef } from 'react'; function ParentComponent() { const someData = useRef(1); // 改变someData.current的逻辑 return <ChildComponent dataRef={someData} />; } interface ChildProps { dataRef: React.MutableRefObject<number>; } function ChildComponent({ dataRef }: ChildProps) { const onClick = () => { // 直接访问current,类型完全明确 console.log(dataRef.current); }; return <button onClick={onClick} type="button">点击</button>; }
这种方式下,子组件可以随时拿到dataRef.current的最新值,而且不需要处理混合类型的ref,类型安全无歧义。
3. 如果非要用forwardRef,怎么处理类型问题
如果你坚持要用forwardRef传递数据,需要先区分ref的类型(函数式ref还是对象式ref),因为函数式ref是用来接收实例的回调,根本不适合存储数据,所以我们只处理对象式ref的情况:
import { forwardRef, useRef } from 'react'; function ParentComponent() { const someData = useRef(1); return <ChildComponent ref={someData} />; } const ChildComponent = forwardRef<number>((props, ref) => { const onClick = () => { // 先判断ref是否为对象式ref if (ref && 'current' in ref) { const currentValue = ref.current; console.log(currentValue); // 类型为number | null } }; return <button onClick={onClick} type="button">点击</button>; });
如果你能100%确定父组件传递的是对象式ref(比如自己维护的代码),也可以强制类型转换,但要注意风险(如果后续改成函数式ref会报错):
const onClick = () => { const refObj = ref as React.MutableRefObject<number | null>; console.log(refObj.current); };
总结
- 优先选择普通props传递ref对象的方案,类型安全、符合React设计语义;
- 尽量避免用
forwardRef传递普通数据,否则会引入不必要的类型复杂度; - 若必须用
forwardRef,优先通过类型判断处理对象式ref,而非直接强制转换。
内容的提问来源于stack exchange,提问作者Cash
相关产品推荐
相关产品推荐

