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

React onMouseEnter/onMouseLeave悬停PopUp闪烁循环问题排查

问题产生原因

闪烁是两个问题叠加导致的:

  • 你渲染的PopUp最外层用了fixed inset-0的全屏定位,还额外加了一个inset-0 z-40的全屏遮罩层,这两个元素渲染出来之后会直接覆盖在原本的按钮上方。鼠标悬停在按钮上触发PopUp渲染的瞬间,鼠标的悬停对象就从按钮变成了盖在上面的PopUp/遮罩层,按钮直接触发onMouseLeave把PopUp关掉;PopUp消失后鼠标又落回按钮上,再次触发onMouseEnter渲染PopUp,循环往复就出现了持续闪烁的现象。
  • 定时器逻辑存在bug:一是你把定时器ID存在普通变量TooltipTimeout里,组件每次重渲染都会重置这个变量,根本拿不到之前的定时器ID;二是你用clearInterval去清除setTimeout创建的定时器,两者API不匹配,根本清不掉,会出现残留定时器意外修改状态的问题。
修复方案

按以下步骤调整即可:

  1. 解决遮罩层抢鼠标事件的问题,两种方案选其一即可:
    • 做居中全屏模态式弹窗:给全屏遮罩层和PopUp外层的fixed容器加上pointer-events-none类,让鼠标事件可以穿透遮罩层,不会打断按钮的悬停状态;PopUp的内容容器再加pointer-events-auto,保证弹窗内的链接、按钮可以正常点击。
    • 做跟随按钮的小提示Tooltip:把父容器设为relative,PopUp改成absolute定位放在按钮旁边,同时把onMouseEnter和onMouseLeave绑定到这个共同父容器上,鼠标在按钮或者PopUp上时都不会触发关闭,交互更自然。
  2. 修正定时器逻辑:用useRef存储定时器ID,保证重渲染时ID不会丢失;清除定时器时统一用clearTimeout匹配setTimeout,同时在组件卸载时补充清除逻辑,避免内存泄漏。
修复后完整代码
import { useState, useRef, useEffect } from 'react';
import { TooltipClose } from "../../../utils/svg";

export default function CustomTooltipsRed() {
    const [activeToolTip, setActiveToolTip] = useState(false);
    // 用useRef存定时器ID,重渲染不丢失
    const TooltipTimeout = useRef(null);

    const showToolTip = () => {
        // 先清掉之前的定时器,避免重复触发
        if (TooltipTimeout.current) clearTimeout(TooltipTimeout.current);
        TooltipTimeout.current = setTimeout(() => {
            setActiveToolTip(true);
        }, 50);
    };

    const hideToolTip = () => {
        setActiveToolTip(false);
        // 用clearTimeout清除setTimeout
        if (TooltipTimeout.current) {
            clearTimeout(TooltipTimeout.current);
            TooltipTimeout.current = null;
        }
    };

    // 组件卸载时清定时器
    useEffect(() => {
        return () => {
            if (TooltipTimeout.current) clearTimeout(TooltipTimeout.current);
        }
    }, []);

    return (
        <div className="flex items-center justify-center ">
            <button
                className="bg-pink-500 text-white font-bold uppercase text-sm px-6 py-3 rounded shadow mr-1 mb-1 "
                onMouseEnter={() => showToolTip()}
                onMouseLeave={() => hideToolTip()}
            >
                Hover button
            </button>

            {activeToolTip ? (
                <>
                    <div className="justify-center items-center flex fixed inset-0 outline-none focus:outline-none pointer-events-none">
                        <div className="relative w-auto my-6 mx-auto max-w-xl pointer-events-auto">
                            {/*content*/}
                            <div className="border-0 rounded-lg shadow-lg relative flex flex-col w-full bg-[#F43F5E] outline-none">
                                {/*header*/}
                                <div className="flex items-center justify-start p-2 rounded-t">
                                    <div className="mr-2">
                                        <i><TooltipClose /></i>
                                    </div>
                                    <h3 className="text-base font-semibold text-white">
                                        P1 - Priority Issue
                                    </h3>
                                </div>
                                {/*body*/}
                                <div className="relative p-6 flex-auto bg-[#1E293B] rounded-b-lg">
                                    <p className="text-[#E2E8F0] leading-relaxed">
                                        We have detected that your tenant has legacy protocols enabled.
                                        Why is this an issue? Legacy protocols can not enforce multi factor
                                        authentication and are considered a security risk.
                                    </p>
                                    <a href="/" className="text-[#E2E8F0] text-xs">Read More</a>
                                </div>
                            </div>
                        </div>
                    </div>
                    {/* 遮罩层加pointer-events-none,不拦截鼠标事件 */}
                    <div className="inset-0 z-40 pointer-events-none"></div>
                </>
            ) : null}
        </div >
    );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 17:48:17