如何在React中获取嵌套二级组件Baz的聚合Ref列表?
获取所有Baz组件的聚合Ref列表方案
要实现跨多层组件收集所有Baz的Ref,需要通过逐层传递收集逻辑来实现,以下是两种可行方案:
方案一:通过回调Props收集
1. 修正Baz组件,支持接收外部Ref
const Baz = React.forwardRef<HTMLDivElement>((_, ref) => { return <div ref={ref}>Test</div>; });
2. 修改Bar组件,内部收集Baz的Ref并传递给父组件
const Bar = ({ onBazRefsCollected }: { onBazRefsCollected: (refs: Array<HTMLDivElement | null>) => void }) => { const bazRefs = React.useRef<Array<HTMLDivElement | null>>([]); // 组件挂载/更新后,将内部Baz的Ref数组传递给父组件 React.useEffect(() => { onBazRefsCollected(bazRefs.current); // 卸载时清空对应Ref,避免无效引用 return () => onBazRefsCollected([]); }, [onBazRefsCollected]); return ( <div> {[0, 1, 2].map((_, index) => ( <Baz key={index} ref={(el) => (bazRefs.current[index] = el)} /> ))} </div> ); };
3. 在Foo组件中聚合所有Baz的Ref
const Foo = () => { const allBazRefs = React.useRef<Array<HTMLDivElement | null>>([]); // 处理每个Bar传递的Ref数组,更新总列表 const handleBazRefsCollected = (barIndex: number, refs: Array<HTMLDivElement | null>) => { // 定位当前Bar在总列表中的位置,替换旧的Ref const startPos = barIndex * 3; allBazRefs.current.splice(startPos, refs.length, ...refs); }; return ( <div> {[0, 1, 2, 3].map((i) => ( <Bar key={i} onBazRefsCollected={(refs) => handleBazRefsCollected(i, refs)} /> ))} </div> ); };
方案二:通过ForwardRef让Bar暴露内部Baz的Ref数组
1. 修正Baz组件(同方案一)
const Baz = React.forwardRef<HTMLDivElement>((_, ref) => { return <div ref={ref}>Test</div>; });
2. 修改Bar组件,通过ForwardRef暴露内部Baz的Ref数组
const Bar = React.forwardRef<Array<HTMLDivElement | null>>((_, ref) => { const bazRefs = React.useRef<Array<HTMLDivElement | null>>([]); // 将内部Baz的Ref数组传递给父组件的Ref React.useEffect(() => { if (typeof ref === 'function') { ref(bazRefs.current); } else if (ref) { ref.current = bazRefs.current; } }, [ref]); return ( <div> {[0, 1, 2].map((_, index) => ( <Baz key={index} ref={(el) => (bazRefs.current[index] = el)} /> ))} </div> ); });
3. 在Foo组件中聚合所有Baz的Ref
const Foo = () => { const barRefs = React.useRef<Array<Array<HTMLDivElement | null>>>([]); const allBazRefs = React.useRef<Array<HTMLDivElement | null>>([]); // 当Bar的Ref数组更新时,合并为一维数组 React.useEffect(() => { allBazRefs.current = barRefs.current.flat(); }, [barRefs.current]); return ( <div> {[0, 1, 2, 3].map((i) => ( <Bar key={i} ref={(refs) => (barRefs.current[i] = refs)} /> ))} </div> ); };
注意事项
- 所有列表项必须添加
key属性,避免React渲染警告; - 组件卸载时需清理对应Ref引用,防止内存泄漏;
- 若Baz的数量动态变化,需在Bar组件中监听数量变化,调整Ref收集逻辑。
内容的提问来源于stack exchange,提问作者Matthieu Riegler
相关产品推荐
相关产品推荐

