如何在React的VariableSizeList中动态计算组件高度?
解决react-window VariableSizeList动态计算子项高度的问题
问题分析
你尝试用div的onLoad事件获取高度,但onLoad仅适用于图片、脚本等资源型元素,普通div不会触发该事件,导致高度数组始终为空,所有子项高度被设为0而堆叠在一起。
解决方案
以下是调整后的代码,核心是通过useEffect监听子组件挂载,获取真实高度后更新状态,并通知VariableSizeList重新计算高度:
//@ts-ignore import React, { useRef, useState, useEffect } from 'react'; import { VariableSizeList, ListChildComponentProps } from 'react-window'; import { Box, ListItem, ListItemText } from '@mui/material'; const HistoryList = () => { // 初始化高度数组,长度匹配itemCount,默认值设为ListItem的常规高度 const [statComponentHeights, setStatComponentHeights] = useState<number[]>(new Array(10).fill(48)); const listRef = useRef<VariableSizeList>(null); // 保存列表实例的ref const ListItemComponent = (props: ListChildComponentProps) => { const licRef = useRef<HTMLDivElement>(null); const { index } = props; // 组件挂载后获取真实DOM高度 useEffect(() => { if (licRef.current) { const realHeight = licRef.current.clientHeight; // 仅当高度变化时更新状态,避免冗余重渲染 if (statComponentHeights[index] !== realHeight) { setStatComponentHeights(prev => { const newHeights = [...prev]; newHeights[index] = realHeight; // 按索引精准更新对应子项高度 return newHeights; }); } } }, [index, statComponentHeights]); // 高度更新后,通知列表重新计算布局 useEffect(() => { if (listRef.current && statComponentHeights[index] > 0) { // 重置指定索引后的布局,react-window官方推荐的更新方式 listRef.current.resetAfterIndex(index, true); } }, [statComponentHeights[index], index]); return ( <div ref={licRef} style={props.style}> <ListItem sx={{ color: 'white' }} component="div" disablePadding> <ListItemText primary={`Item ${index}`} /> </ListItem> </div> ); }; const getItemSize = (index: number) => { return statComponentHeights[index]; }; return ( <Box> <VariableSizeList ref={listRef} height={400} width={300} itemSize={getItemSize} itemCount={10} > {ListItemComponent} </VariableSizeList> </Box> ); }; export default HistoryList;
关键说明
- 初始化高度数组:提前创建与
itemCount长度一致的数组,设置合理默认高度(比如Material-UI ListItem的常规高度48px),避免初始渲染时子项完全堆叠 - useEffect获取高度:子组件挂载后通过ref读取DOM的
clientHeight,按索引精准更新对应子项的高度,避免顺序混乱 - resetAfterIndex方法:调用react-window提供的官方方法,通知列表重新计算指定索引后的子项布局,比强制全局重渲染更高效
- 状态更新优化:仅当真实高度与缓存高度不一致时才更新状态,减少不必要的重渲染次数
内容的提问来源于stack exchange,提问作者harharprogrammer
相关产品推荐
相关产品推荐

