
19 之前必须包一层
在 React 18 里,ref 是特殊 prop,函数组件收不到它。要让父组件拿到内部的 DOM 节点,得用 forwardRef 把 ref 转发进来:
// 18 写法const MyInput = forwardRef(function MyInput(props, ref) { return <input {...props} ref={ref} />})这一层壳的唯一作用就是「让 ref 通过」。
19 起它就是个普通 prop
// 19 写法function MyInput({ value, onChange, ref }) { return <input value={value} onChange={onChange} ref={ref} />}官方发布说明里的原话是:函数组件可以直接把 ref 当 prop 访问,新的函数组件不再需要 forwardRef(React 19 发布说明)。
forwardRef 还没有删除,但参考页上已经挂了弃用横幅。读旧代码时会见到它,新代码不必再写。
一个例外:类组件收到的 ref 仍然是组件实例,不会作为 prop 传进去。
ref 回调可以返回清理函数
19 起,ref 回调允许返回一个清理函数,卸载时 React 调用它:
<div ref={node => { const observer = new ResizeObserver(() => {}) observer.observe(node) return () => observer.disconnect() }}/>旧写法是在回调里判断 node === null 来做清理。官方说将来会弃用「卸载时以 null 调用 ref 回调」这种做法,新代码用返回清理函数的形式。
TypeScript 上有个细节:返回值必须是清理函数(或什么都不返回)。ref={c => (instance = c)} 会被拒,因为它返回了赋值结果;写成块体 ref={c => { instance = c }} 就对了。
19.3 起 Fragment 也能收 ref
React 19.3 给 <Fragment> 加了 ref,拿到的是一个 FragmentInstance,可以在它上面添加事件监听、读取子节点位置。需要给一组相邻元素整体挂监听或量位置时有用(React 19.3)。
与相邻几篇的关系
useRef 本身怎么用、什么时候不该用,见 useRef;要定制「父组件能拿到什么」,用 useImperativeHandle,见 useImperativeHandle;forwardRef 退场之后,高阶组件只要透传 props 就顺带带上了 ref,见 高阶组件(HOC)。
分享文章
生成精美分享图或复制链接,与更多人分享本文。
继续阅读
换条路线
从其他文章中稳定抽取
最后更新于 ,距今已过 190 天
部分内容可能已过时