迭代渲染过程中如何跟踪div的动态高度增量?
解决方案
核心原因
你在map遍历中直接读取DOM高度的写法无效,是因为React的渲染流程是先同步计算完所有待渲染的JSX节点,再一次性更新到DOM树上。遍历执行的阶段属于render阶段,此时所有新的列表项都还没挂载到页面,你读到的永远是上一次渲染完成后的总高度,自然拿不到每轮迭代的增量。
推荐解决方法
方法1:使用ref回调逐个监听列表项挂载
这种方式不需要额外依赖,性能开销最小,适合自定义列表项组件的场景:
- 首先定义存储上一次高度的ref和跟踪容器的ref:
import { useRef } from 'react'; // 组件内部逻辑 // 存储上一次测量的容器高度 const lastHeightRef = useRef(0); // 绑定你要跟踪高度的目标div const trackContainerRef = useRef(null);
- 修改JSX部分,通过ref回调在每个列表项挂载完成后触发测量:
<div id="divtotrack" ref={trackContainerRef}> {items.map((item) => ( <div key={item.id} ref={(domNode) => { // 仅当列表项DOM挂载、且容器存在时执行测量 if (!domNode || !trackContainerRef.current) return; const currentTotalHeight = trackContainerRef.current.clientHeight; // 计算本次增量 const heightIncrement = currentTotalHeight - lastHeightRef.current; // 此处可执行你需要的增量处理逻辑 console.log('当前列表项对应的高度增量:', heightIncrement); // 更新上一次高度存储 lastHeightRef.current = currentTotalHeight; }} > {/* 注意:React自定义组件首字母必须大写,原来的<item />需要改为<Item /> */} <Item id={item.id} content={item.content} /> </div> ))} </div>
方法2:使用MutationObserver监听容器变化
如果列表项是第三方组件、或不想修改列表项相关代码,可以用MutationObserver监听容器的子节点变化,自动计算增量:
import { useEffect, useRef } from 'react'; // 组件内部逻辑 const trackContainerRef = useRef(null); const lastHeightRef = useRef(0); useEffect(() => { const container = trackContainerRef.current; if (!container) return; // 初始化记录容器初始高度 lastHeightRef.current = container.clientHeight; // 创建监听器 const observer = new MutationObserver((mutationList) => { // 仅当有新子节点新增时执行测量 const hasNewNode = mutationList.some(mutation => mutation.addedNodes.length > 0); if (!hasNewNode) return; const currentTotalHeight = container.clientHeight; const heightIncrement = currentTotalHeight - lastHeightRef.current; // 处理增量逻辑 console.log('高度增量:', heightIncrement); lastHeightRef.current = currentTotalHeight; }); // 开启监听 observer.observe(container, { childList: true, // 监听子节点变化 subtree: true // 监听所有后代节点变化 }); // 组件卸载时销毁监听器 return () => observer.disconnect(); }, []);
注意事项
- 如果列表项内部包含异步加载的资源(比如图片、异步渲染的富文本),需要等资源加载完成后再测量高度,否则会出现增量计算不准的问题
- 不要在render阶段(map遍历的回调函数内)直接操作或读取DOM,所有DOM相关的操作都要放在挂载完成后的回调/副作用中执行
内容的提问来源于stack exchange,提问作者Richardson
相关产品推荐
相关产品推荐

