React中如何正确传递DOM元素引用给平滑滚动组件?
React 平滑滚动组件的DOM引用传递优化方案
问题场景
我实现了一个平滑滚动的工具组件:
const SmoothScroller = ({ text, target, }: { text: string target: HTMLElement | null }) => { const scrollToTarget = () => { target?.scrollIntoView({ behavior: 'smooth', }) } return <a onClick={scrollToTarget}>{text}</a> }
使用时需要创建DOM元素引用并传入:
const ref = useRef<HTMLParagraphElement>(null) return <> <SmoothScroller target={ref.current} text="Scroll to paragraph" /> <p ref={ref} className="read-the-docs"> Click on the Vite and React logos to learn more </p> </>
但这种方式无法正常工作,因为渲染时ref.current可能为null,且后续ref.current更新后不会触发组件重新传参。虽然可以改成传递获取元素的函数(target: () => HTMLElement | null),但存在更优方案。
最优解决方案:传递React Ref对象而非ref.current
直接将整个Ref对象传递给组件,而不是它的current属性。Ref对象在组件生命周期内是稳定的,不会随重渲染变化,且点击时可以获取最新的DOM元素引用。
修改后的组件代码
import React from 'react' const SmoothScroller = ({ text, targetRef, }: { text: string targetRef: React.RefObject<HTMLElement> }) => { const scrollToTarget = () => { // 点击时才获取最新的current值 targetRef.current?.scrollIntoView({ behavior: 'smooth', }) } return <a onClick={scrollToTarget}>{text}</a> }
使用方式
const ref = useRef<HTMLParagraphElement>(null) return <> <SmoothScroller targetRef={ref} // 直接传递ref对象 text="Scroll to paragraph" /> <p ref={ref} className="read-the-docs"> Click on the Vite and React logos to learn more </p> </>
方案优势
- 避免初始null问题:点击时才访问
targetRef.current,此时DOM元素已经挂载完成,能确保获取到有效的元素引用(只要目标元素存在)。 - 稳定性更高:Ref对象本身不会在重渲染时创建新实例,不会触发
SmoothScroller组件的不必要重渲染。 - 符合React最佳实践:直接传递Ref对象是React中跨组件传递DOM引用的标准方式,代码更直观易懂。
内容的提问来源于stack exchange,提问作者Michał Turczyn
相关产品推荐
相关产品推荐

