You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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;

关键说明

  1. 初始化高度数组:提前创建与itemCount长度一致的数组,设置合理默认高度(比如Material-UI ListItem的常规高度48px),避免初始渲染时子项完全堆叠
  2. useEffect获取高度:子组件挂载后通过ref读取DOM的clientHeight,按索引精准更新对应子项的高度,避免顺序混乱
  3. resetAfterIndex方法:调用react-window提供的官方方法,通知列表重新计算指定索引后的子项布局,比强制全局重渲染更高效
  4. 状态更新优化:仅当真实高度与缓存高度不一致时才更新状态,减少不必要的重渲染次数

内容的提问来源于stack exchange,提问作者harharprogrammer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 12:52:47