如何在Next.js路由场景下正确使用Locomotive Scroll 解决滚动实例重叠问题
问题原因分析
- 你当前的
scroll实例是useEffect内部的局部变量,路由跳转后无法拿到上一次渲染生成的旧实例,导致旧实例始终没有被真正销毁,每次渲染都新建实例自然会出现重叠 useEffect没有传入依赖数组,每次组件渲染都会重复执行导入和初始化逻辑,进一步加剧实例重复问题- 刚
new完实例就立刻调用destroy再延时init的逻辑是错误的,你销毁的是刚创建的新实例,而不是上一个路由的旧实例
正确实现方案
以下是Pages路由下_app.js的修正代码:
import { useEffect, useRef } from 'react' import { useRouter } from 'next/router' function MyApp({ Component, pageProps }) { // 存储滚动实例,跨渲染/路由变化可访问 const scrollRef = useRef(null) // 存储定时器ID,避免多个定时器叠加 const initTimeoutRef = useRef(null) const router = useRouter() // 滚动实例初始化通用方法 const initScroll = async () => { // 初始化前先销毁已有旧实例 if (scrollRef.current) { scrollRef.current.destroy() scrollRef.current = null } // 动态导入locomotive-scroll const locomotiveModule = await import("locomotive-scroll") // 清理上一个未执行的定时器 if (initTimeoutRef.current) clearTimeout(initTimeoutRef.current) // 等待新页面DOM完全渲染后再初始化 initTimeoutRef.current = setTimeout(() => { const scrollContainer = document.querySelector("[data-scroll-container]") if (!scrollContainer) return scrollRef.current = new locomotiveModule.default({ el: scrollContainer, smooth: true, smoothMobile: false, resetNativeScroll: true, }) }, 300) } useEffect(() => { // 首次进入页面初始化实例 initScroll() // 监听路由跳转完成事件,每次跳转后重新初始化 const handleRouteChange = () => initScroll() router.events.on('routeChangeComplete', handleRouteChange) // 页面卸载/关闭时清理所有资源 return () => { router.events.off('routeChangeComplete', handleRouteChange) if (initTimeoutRef.current) clearTimeout(initTimeoutRef.current) if (scrollRef.current) { scrollRef.current.destroy() scrollRef.current = null } } }, []) return ( <main data-scroll-container> <Component {...pageProps} /> </main> ) } export default MyApp
如果你使用的是Next.js 13+ App Router,只需要把路由监听逻辑换成监听usePathname返回的路径变化,核心逻辑完全一致。
内容的提问来源于stack exchange,提问作者Denis Kunitsyn
相关产品推荐
相关产品推荐

