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

如何重构MUI Tooltip封装组件以减少代码重复?

优化后的代码实现
import { TooltipProps } from '@mui/material';
import { useRef, useState, useCallback } from 'react';
import { Tooltip } from '../tooltip/Tooltip';

interface TableTooltipProps extends TooltipProps {
  selector?: string;
}

export function TableTooltip({
  selector = '.MuiTableContainer-root',
  children,
  ...props
}: TableTooltipProps) {
  const [isScrolling, setIsScrolling] = useState(false);
  const timeoutIdRef = useRef<number | null>(null);
  const elementRef = useRef<HTMLTableCellElement>(null);
  const tableElementRef = useRef<HTMLElement | null>(null);

  // 统一获取表格元素,仅初始化一次
  const getTableElement = useCallback(() => {
    if (!tableElementRef.current && elementRef.current) {
      tableElementRef.current = elementRef.current.closest(selector) as HTMLElement;
    }
    return tableElementRef.current;
  }, [selector]);

  const handleScroll = useCallback(() => {
    console.warn('scrolling');
    setIsScrolling(true);
    
    const tableElement = getTableElement();
    tableElement?.removeEventListener('scroll', handleScroll);
    console.warn('aborted');

    if (timeoutIdRef.current) {
      clearTimeout(timeoutIdRef.current);
    }
    timeoutIdRef.current = window.setTimeout(() => {
      setIsScrolling(false);
    }, 500);
  }, [getTableElement]);

  const attachToScrollEvent = useCallback(() => {
    const tableElement = getTableElement();
    if (tableElement) {
      console.warn('added');
      tableElement.addEventListener('scroll', handleScroll);
    }
  }, [getTableElement, handleScroll]);

  const detachFromScrollEvent = useCallback(() => {
    const tableElement = getTableElement();
    if (tableElement) {
      console.warn('removed');
      tableElement.removeEventListener('scroll', handleScroll);
    }
  }, [getTableElement, handleScroll]);

  return !isScrolling ? (
    <>
      <Tooltip
        onOpenCallback={attachToScrollEvent}
        onCloseCallback={detachFromScrollEvent}
        {...props}
      >
        {children}
      </Tooltip>
      <td className="html-element-dummy" style={{ display: 'none' }} ref={elementRef} />
    </>
  ) : (
    <>
      {children}
    </>
  );
}
核心优化点说明
  • 复用表格元素引用:新增tableElementRef缓存表格DOM节点,通过getTableElement统一获取逻辑,避免在三个回调中重复调用closest(selector)
  • 消除重复判断:移除了每个函数中重复的ref.current检查,统一在getTableElement中处理
  • 优化定时器存储:将timeoutId从useState改为useRef,因为定时器ID无需触发组件重渲染,用ref更高效且避免状态不同步
  • 缓存回调函数:用useCallback包裹所有事件回调,避免组件每次渲染生成新函数实例,减少不必要的事件解绑/绑定操作
  • 类型安全提升:给元素ref指定明确的HTML类型,替换原有的any类型,增强代码健壮性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 19:36:20