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

如何将react-virtual的useVirtual与Material-UI Select集成实现选项虚拟化

Material-UI Select 大量选项卡顿优化方案

问题背景

当Material-UI Select的选项数量超过200条时会出现卡顿,属于官方已知问题,原因是默认会全量渲染所有MenuItem节点,大量DOM节点占用内存导致交互卡顿。

现有react-virtual实现的修复

你当前的useVirtual实现存在几处可优化的点,调整后即可正常运行:

  • ref绑定对象错误:你将parentRef绑定到了Menu根容器,实际滚动容器是内部的MenuList,应该把ref绑定到MenuListProps的ref属性上
  • 值类型不匹配:初始state的value是数字类型,而MenuItem的value被转成了字符串,导致初始选中状态不生效
  • 缺少选中项自动定位逻辑:打开下拉时不会自动滚动到当前选中的选项位置

修正后的完整代码如下:

import * as React from "react";
import Select from "@material-ui/core/Select";
import MUIMenuItem from "@material-ui/core/MenuItem";
import { useVirtual } from "react-virtual";

export default function Demo() {
  const parentRef = React.useRef<HTMLDivElement>(null);
  const [value, setValue] = React.useState<string>("1"); // 调整为字符串类型和MenuItem的value匹配

  const rowVirtualizer = useVirtual({
    size: 10000,
    parentRef,
    estimateSize: React.useCallback(() => 35, []),
    overscan: 5
  });

  // 可选:下拉打开时自动滚动到选中项
  React.useEffect(() => {
    if (parentRef.current && value) {
      const targetIndex = Number(value);
      rowVirtualizer.scrollToIndex(targetIndex);
    }
  }, [value, rowVirtualizer]);

  return (
    <Select
      MenuProps={{
        style: {
          width: `400px`,
        },
        anchorOrigin: {
          vertical: "bottom",
          horizontal: "left"
        },
        getContentAnchorEl: null,
        MenuListProps: {
          ref: parentRef, // ref绑定到MenuList,也就是实际滚动容器
          style: {
            height: "200px", // 滚动容器高度放在MenuList上
            overflow: "auto",
            width: "100%",
            position: "relative"
          }
        }
      }}
      value={value}
      onChange={(e: React.ChangeEvent<{ value: unknown }>) => setValue(e.target.value as string)}
    >
      <div style={{ height: `${rowVirtualizer.totalSize}px`, position: "relative" }}>
        {rowVirtualizer.virtualItems.map(({ index, size, start }) => (
          <MUIMenuItem
            style={{
              position: "absolute",
              top: 0,
              left: 0,
              width: "100%",
              height: `${size}px`,
              transform: `translateY(${start}px)`
            }}
            key={index}
            value={String(index)}
          >
            <div>{index}</div>
          </MUIMenuItem>
        ))}
      </div>
    </Select>
  );
}

其他可选实现方案

  • 使用react-window实现虚拟化:Material-UI官方提供了基于react-window的虚拟化Select示例,适配性更强,无需手动处理定位逻辑
  • 升级到支持原生虚拟化的MUI X Select组件:高阶版本的MUI X Select内置了虚拟化支持,只需配置virtualize属性即可开启
  • 搭配搜索过滤功能:如果选项量超过10万条,可以在Select顶部加搜索输入框,先过滤缩小选项范围再渲染,进一步降低渲染压力

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 19:45:01