Next.js 13滚动时状态不更新问题求助
问题原因与解决方法
问题根源
你的代码中useEffect的依赖数组包含了offsetTop,这会引发两个关键问题:
- 不必要的重复执行:每次
offsetTop更新时,useEffect都会重新运行,反复移除旧的滚动监听并添加新的监听。由于初始offsetTop默认值是0,首次执行handleScrollEvent时如果window.scrollY也是0,状态不会更新,导致useEffect仅执行一次,但后续滚动时监听可能因绑定逻辑异常失效。 - 监听无法正确绑定/移除:
handleScrollEvent是在useEffect内部定义的函数,每次useEffect执行都会生成新的函数实例。移除监听时使用的是当前实例,无法匹配之前绑定的旧实例,导致旧监听残留、新监听无法正常工作,最终状态始终停留在初始值。
解决方法
修改useEffect的依赖数组为空数组,确保仅在组件挂载时添加一次滚动监听,卸载时移除:
'use client'; ... const Navbar = (navbarProps: navbarProps) => { const [offsetTop, setOffsetTop] = useState(0); useEffect(() => { const handleScrollEvent = () => { setOffsetTop(window.scrollY); }; // 初始化获取滚动位置 handleScrollEvent(); // 添加滚动监听 window.addEventListener('scroll', handleScrollEvent, { passive: true }); // 清理函数:组件卸载时移除监听 return () => { window.removeEventListener('scroll', handleScrollEvent); }; }, []); // 空依赖数组,仅在组件挂载/卸载时执行 ... }
额外说明
- 如果页面的滚动容器不是
window(比如自定义滚动的div),需要将监听对象改为对应的容器元素,同时用element.scrollTop代替window.scrollY。 - 若需进一步优化性能,可使用
useCallback包裹handleScrollEvent,但在当前场景下,空依赖数组的useEffect已足够保证监听逻辑稳定运行。
内容的提问来源于stack exchange,提问作者mbelleri
相关产品推荐
相关产品推荐

