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

如何解决Material-UI Menu重渲染后滚动位置重置问题?

解决Material-UI Menu组件重渲染时滚动位置重置的问题

我刚遇到过类似的情况,来给你拆解下原因和解决办法哈~

为什么Menu会重置滚动位置,而原生<ul>不会?

原生<ul>在重渲染时,只是更新内部的子元素,DOM容器本身没有被卸载或重建,所以浏览器会自动保留它的滚动位置。但Material-UI的Menu组件内部结构更复杂:它是基于Popover实现的,列表内容被包裹在Paper和MenuList组件中。当你的状态更新(比如items变化)时,Menu内部可能因为组件的重新渲染逻辑,导致滚动容器(也就是MenuList对应的DOM元素)被重新创建,或者组件的key发生变化触发了卸载再挂载,这样滚动位置就会被重置。

解决办法:手动保存并恢复滚动位置

我们可以通过ref记录滚动容器的滚动位置,在组件更新后把位置恢复回去,具体步骤如下:

1. 类组件版本

首先要精准拿到Menu内部负责滚动的元素,也就是MenuList。你可以自定义Menu内部的MenuList并给它加ref:

import { Menu, MenuList } from '@material-ui/core';

class YourMenuComponent extends React.Component {
  // 用来保存滚动容器的ref
  menuListRef = React.createRef();
  // 记录滚动位置
  scrollPosition = 0;

  // 监听滚动事件,保存当前滚动位置
  handleMenuScroll = (e) => {
    this.scrollPosition = e.target.scrollTop;
  };

  // 组件更新后恢复滚动位置
  componentDidUpdate(prevProps) {
    // 当items变化时(也就是触发重渲染的原因)
    if (prevProps.items !== this.props.items) {
      const scrollContainer = this.menuListRef.current;
      if (scrollContainer) {
        scrollContainer.scrollTop = this.scrollPosition;
      }
    }
  }

  render() {
    const { onChange, items } = this.props;
    return (
      <Menu onChange={onChange}>
        <MenuList 
          ref={this.menuListRef} 
          onScroll={this.handleMenuScroll}
        >
          {items}
        </MenuList>
      </Menu>
    );
  }
}

2. 函数组件版本(Hook写法)

如果是函数组件,可以用useRef和useEffect来实现:

import { Menu, MenuList } from '@material-ui/core';
import { useRef, useEffect } from 'react';

const YourMenuComponent = ({ onChange, items }) => {
  const menuListRef = useRef(null);
  const scrollPosition = useRef(0);

  const handleMenuScroll = (e) => {
    scrollPosition.current = e.target.scrollTop;
  };

  useEffect(() => {
    const scrollContainer = menuListRef.current;
    if (scrollContainer) {
      scrollContainer.scrollTop = scrollPosition.current;
    }
  }, [items]); // 当items变化时触发恢复

  return (
    <Menu onChange={onChange}>
      <MenuList 
        ref={menuListRef} 
        onScroll={handleMenuScroll}
      >
        {items}
      </MenuList>
    </Menu>
  );
};

额外提示:减少不必要的重渲染

如果你的items每次都是新创建的数组(比如用map生成时没有稳定的key),会导致Menu频繁重渲染。可以给每个菜单项加上唯一的key,或者用React.memo包裹菜单项组件,减少不必要的渲染,这样也能间接降低滚动位置丢失的概率。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:32:32