使用React Hooks检测滚动方向:状态未更新导致功能失效的问题
解决React Hooks滚动方向检测的状态更新问题
我来帮你排查这个问题!你遇到的核心问题是闭包陷阱导致的:你的useEffect依赖项是空数组,这意味着handleScroll函数只会在组件初始渲染时创建一次,它捕获的scollPosition永远是初始的0。哪怕你调用了setSrollPosition更新状态,handleScroll里的scollPosition还是旧值,自然没法正确判断滚动方向。
下面给你两种可行的解决方案:
方案一:更新useEffect的依赖项
把scrollPosition(顺便修正了你变量名的拼写错误,scoll→scroll,避免后续混淆)加入useEffect的依赖数组,这样每次状态更新时,都会重新创建handleScroll函数,确保它能拿到最新的状态值:
import { useState, useEffect } from 'react'; function ScrollDirectionDetector() { const [scrollPosition, setScrollPosition] = useState(0); const handleScroll = () => { const position = window.pageYOffset; console.log(position); if (position > scrollPosition) { console.log("down"); } else { console.log("up"); } setScrollPosition(position); }; useEffect(() => { window.addEventListener("scroll", handleScroll, { passive: true }); return () => window.removeEventListener("scroll", handleScroll); }, [scrollPosition]); // 加入状态作为依赖项 return <div>滚动页面查看方向日志</div>; } export default ScrollDirectionDetector;
方案二:使用useRef保存滚动位置(性能更优)
如果不想每次状态更新都重复解绑/绑定滚动事件,可以用useRef存储滚动位置。ref的.current属性是可变的,不会被闭包捕获旧值,能始终拿到最新数据,同时减少不必要的事件操作:
import { useState, useEffect, useRef } from 'react'; function ScrollDirectionDetector() { const scrollPositionRef = useRef(0); const handleScroll = () => { const currentPosition = window.pageYOffset; console.log(currentPosition); if (currentPosition > scrollPositionRef.current) { console.log("down"); } else { console.log("up"); } scrollPositionRef.current = currentPosition; // 直接更新ref的current属性 }; useEffect(() => { window.addEventListener("scroll", handleScroll, { passive: true }); return () => window.removeEventListener("scroll", handleScroll); }, []); // 依赖项保持空数组即可 return <div>滚动页面查看方向日志</div>; } export default ScrollDirectionDetector;
两种方案都能解决你的问题,方案二更适合滚动频繁的场景,因为它避免了重复绑定事件的开销。
内容的提问来源于stack exchange,提问作者Lunkai Yang
相关产品推荐
相关产品推荐

