React中不依赖外部库实现onScroll事件防抖的方法
问题:scroll事件重复触发导致多次打印的解决办法
问题描述
给滚动容器绑定onScroll事件后,即便仅触发一次keydown事件(经monitorEvents()验证),控制台仍会多次打印scrolled。要求在不依赖外部库的前提下,确保每次滚动操作仅触发一次打印,且必须通过监听scroll事件实现(不改用keydown)。
原代码:
import "./App.css"; function App() { return ( <section onClick={() => console.log("clicked")} onScroll={() => console.log("scrolled")} style={{ height: "100vh", width: "100vw", overflow: "scroll" }} > <p style={{ height: "300vh" }}>hi</p> </section> ); } export default App;
解决方案
方案1:防抖(Debounce)—— 滚动停止后触发一次
防抖的核心逻辑是:每次触发scroll事件时清除之前的定时器,重新计时,只有当滚动停止超过设定时长(比如100ms),才执行打印操作。这样一次完整的滚动动作(比如按一次方向键后滚动至停止)只会触发一次打印。
修改后的代码:
import "./App.css"; import { useCallback, useRef } from "react"; function App() { // 保存定时器ID,避免组件重渲染丢失引用 const debounceTimerRef = useRef(null); // 缓存防抖后的回调函数,防止不必要的重渲染 const handleScroll = useCallback(() => { if (debounceTimerRef.current) { clearTimeout(debounceTimerRef.current); } // 滚动停止100ms后执行打印 debounceTimerRef.current = setTimeout(() => { console.log("scrolled"); }, 100); }, []); return ( <section onClick={() => console.log("clicked")} onScroll={handleScroll} style={{ height: "100vh", width: "100vw", overflow: "scroll" }} > <p style={{ height: "300vh" }}>hi</p> </section> ); } export default App;
方案2:节流(Throttle)—— 滚动过程中仅触发一次
如果需要在滚动开始时立即触发打印,之后在设定间隔内不再重复触发,可以使用节流。核心逻辑是记录上次触发的时间戳,每次触发scroll事件时判断是否超过设定间隔,超过则执行打印并更新时间戳。
修改后的代码:
import "./App.css"; import { useCallback, useRef } from "react"; function App() { // 记录上次触发的时间戳 const lastTriggerTimeRef = useRef(0); const handleScroll = useCallback(() => { const now = Date.now(); // 设定200ms的触发间隔,间隔内不重复执行 if (now - lastTriggerTimeRef.current > 200) { console.log("scrolled"); lastTriggerTimeRef.current = now; } }, []); return ( <section onClick={() => console.log("clicked")} onScroll={handleScroll} style={{ height: "100vh", width: "100vw", overflow: "scroll" }} > <p style={{ height: "300vh" }}>hi</p> </section> ); } export default App;
选择建议
- 若需要滚动完全停止后再触发打印,优先选防抖方案,可根据实际场景调整定时器时长(比如100ms~300ms)。
- 若需要滚动开始时立即触发一次打印,之后不再重复触发,选节流方案,间隔时长可按需设置。
内容的提问来源于stack exchange,提问作者engrgolden
相关产品推荐
相关产品推荐

