React中通过cloneElement为子组件设置并访问refs问题
解决React整页滚动组件中Refs未正确绑定的问题
问题根源
你代码里的refs数组是用let直接声明的,函数组件每次渲染都会重新生成这个数组,导致子组件挂载时关联的ref对象和点击按钮时打印的不是同一个实例,所以current始终为undefined。另外,没有用React的useRef来持久化这些引用,导致挂载后引用丢失。
修正后的完整代码
FullPageContainer 组件
import React from "react"; export const FullPageContainer = ({ children, }: { children: React.ReactNode; }) => { // 用useRef持久化refs数组,确保组件生命周期内引用不变 const refs = React.useRef<(React.RefObject<HTMLDivElement>)[]>([]); // 当子组件数量变化时,同步更新refs数组长度 React.useEffect(() => { const childCount = React.Children.count(children); refs.current = Array(childCount).fill(null).map(() => React.createRef<HTMLDivElement>()); }, [children]); const childrenWithProps = React.Children.map(children, (child, index) => { if (React.isValidElement(child)) { // 给每个子组件绑定对应的持久化ref return React.cloneElement(child, { ref: refs.current[index] }); } return child; }); // 实现滚动到指定section的核心函数 const scrollToSection = (index: number) => { const targetSection = refs.current[index]; if (targetSection?.current) { targetSection.current.scrollIntoView({ behavior: "smooth", block: "start" }); } }; return ( <div> <button onClick={() => console.log(refs.current)}>查看Refs状态</button> <button onClick={() => scrollToSection(0)}>滚动到第1屏</button> <button onClick={() => scrollToSection(1)}>滚动到第2屏</button> <button onClick={() => scrollToSection(2)}>滚动到第3屏</button> {childrenWithProps} </div> ); };
FullPageSection 组件
import React from "react"; // 修正forwardRef的类型定义,兼容React的ref传递机制 export const FullPageSection = React.forwardRef<HTMLDivElement, { children: React.ReactNode }>( ({ children }, ref) => { return ( <div ref={ref} style={{ height: "100vh", width: "100%", border: "1px solid #eee", display: "flex", alignItems: "center", justifyContent: "center", fontSize: "3rem", backgroundColor: "#f5f5f5" }} > {children} </div> ); } );
关键改进点
- 持久化引用:用
useRef存储refs数组,保证组件每次渲染时访问的是同一批ref对象,避免引用丢失。 - 动态同步:通过
useEffect监听子组件数量变化,自动调整refs数组长度,适配子组件增删的场景。 - 滚动功能实现:新增
scrollToSection函数,利用原生scrollIntoView实现平滑滚动,满足整页滚动的核心需求。 - 类型优化:修正FullPageSection的forwardRef类型,确保ref传递符合React的类型规范,支持对象ref和回调ref。
内容的提问来源于stack exchange,提问作者user12457151
相关产品推荐
相关产品推荐

