Next.js点击浏览器后退按钮返回列表页自动滚动到顶部如何解决
问题根因
这个自动回到顶部的行为是Next.js的默认路由行为,和React无关。Next.js默认会在每次路由跳转完成后自动将页面滚动位置重置到顶部,你的自定义滚动设置逻辑执行时机和默认逻辑冲突,就会被覆盖。
修复方案
方案1:启用Next.js原生滚动恢复(最省心)
Next.js官方已经提供了滚动恢复的内置支持,不需要自己写context存储滚动位置:
- 如果你用的是Next.js 13+ App Router,直接在
next.config.js中添加如下配置即可:
/** @type {import('next').NextConfig} */ const nextConfig = { experimental: { scrollRestoration: true, }, } module.exports = nextConfig
- 如果你用的是Pages Router,在
_app.js中关闭全局自动滚动即可:
function MyApp({ Component, pageProps, router }) { return <Component {...pageProps} scroll={false} /> }
方案2:调整自定义逻辑的执行时机
如果你要保留自己用context存滚动位置的逻辑,需要修改两个点:
- 避开Next.js默认滚动重置的时机,不要在组件初始
useEffect里设置滚动,改成监听路由完成事件后执行:
import { useRouter } from 'next/router' import { useEffect } from 'react' // 假设你从context中拿到的存储滚动值为savedScrollY const ListComponent = () => { const router = useRouter() useEffect(() => { const restoreScroll = () => { // 确认当前回到列表页后再设置滚动 if (router.pathname === '/list') { window.scrollTo(0, savedScrollY) } } // 路由完全跳转完成后再恢复滚动 router.events.on('routeChangeComplete', restoreScroll) return () => router.events.off('routeChangeComplete', restoreScroll) }, [router, savedScrollY]) // 组件其余逻辑 }
- 优化你的window滚动监听逻辑:在主动调用
scrollTo恢复滚动的100ms内暂时屏蔽监听器的更新,避免主动设置滚动的动作被监听器捕获,误将存储的滚动值覆盖为0。
特殊情况处理
如果你的滚动容器是list组件内部的可滚动区域(不是全局window滚动),需要额外注意:
- 不要用
window.scrollTo,要拿到滚动容器的DOM引用,设置containerRef.current.scrollTop = savedScrollY - 必须等列表的所有产品数据渲染完成、容器高度稳定后再设置滚动位置,否则会因为内容高度不足导致滚动设置失效。
内容的提问来源于stack exchange,提问作者Henry Peregrino
相关产品推荐
相关产品推荐

