React自定义Hook实现鼠标滚轮滚动状态检测问题求助
解决方案:React自定义Hook检测鼠标滚动状态
原代码问题分析
你的实现思路方向正确,但存在两个关键问题:
- 组件卸载时未清理未执行的
setTimeout,可能引发内存泄漏或无效状态更新 - 事件处理内的定时器管理不够严谨,容易出现状态不同步的情况
封装可复用自定义Hook useIsWheeling
下面是封装好的Hook,核心逻辑是滚动触发时立即返回true,滚动停止指定时长后切换为false,同时确保所有副作用在组件卸载时彻底清理:
import { useState, useEffect } from 'react'; function useIsWheeling(timeout = 300) { const [isWheeling, setIsWheeling] = useState(false); let scrollTimer = null; useEffect(() => { const handleWheel = () => { // 滚动触发时立刻将状态设为true setIsWheeling(true); // 清除之前的定时器,重置停止计时 clearTimeout(scrollTimer); // 滚动停止timeout毫秒后,将状态切换为false scrollTimer = setTimeout(() => { setIsWheeling(false); }, timeout); }; window.addEventListener('wheel', handleWheel); // 组件卸载时清理事件监听和定时器 return () => { window.removeEventListener('wheel', handleWheel); clearTimeout(scrollTimer); }; }, [timeout]); return isWheeling; }
在组件中使用该Hook
替换你原来的逻辑,代码会更简洁可靠:
import { useRef, useEffect } from 'react'; import gsap from 'gsap'; import useIsWheeling from './useIsWheeling'; // 导入自定义Hook function YourComponent() { const svgHeightRef = useRef(null); const isWheeling = useIsWheeling(300); // 可自定义延迟时长,默认300ms useEffect(() => { if (isWheeling) { gsap.to(svgHeightRef.current, { value: 200, duration: 0.5 }); } else { gsap.to(svgHeightRef.current, { value: 500, duration: 1 }); } }, [isWheeling]); // 组件其他逻辑... return ( {/* 你的JSX结构,示例引用svgHeightRef的元素 */} <svg height={svgHeightRef.current?.value || 500}>...</svg> ); }
关键优化说明
- 内存泄漏防护:组件卸载时同时移除事件监听和清除定时器,避免无效的状态更新操作
- 状态同步严谨:每次滚动事件触发都会重置定时器,确保只有在滚动完全停止后才切换状态
- 复用性强:封装成Hook后,可在任意需要检测滚动状态的组件中直接调用
内容的提问来源于stack exchange,提问作者Reynald Lamury
相关产品推荐
相关产品推荐

