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

Next.js 13滚动时状态不更新问题求助

问题原因与解决方法

问题根源

你的代码中useEffect的依赖数组包含了offsetTop,这会引发两个关键问题:

  1. 不必要的重复执行:每次offsetTop更新时,useEffect都会重新运行,反复移除旧的滚动监听并添加新的监听。由于初始offsetTop默认值是0,首次执行handleScrollEvent时如果window.scrollY也是0,状态不会更新,导致useEffect仅执行一次,但后续滚动时监听可能因绑定逻辑异常失效。
  2. 监听无法正确绑定/移除: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 05:46:30