Next.js 13无限滚动:返回时保留数据与滚动位置方案咨询
在Next.js 13中恢复无限滚动的已加载数据与滚动位置
恢复滚动位置
结合sessionStorage和Next.js路由事件,就能实现离开页面时保存滚动位置、返回时自动恢复的效果:
'use client'; import { useEffect } from 'react'; import { usePathname, useRouter } from 'next/navigation'; export default function InfiniteScrollList() { const pathname = usePathname(); const router = useRouter(); // 离开页面时保存滚动高度 useEffect(() => { const saveScrollPos = () => { sessionStorage.setItem(`scroll_pos_${pathname}`, window.scrollY.toString()); }; // 监听浏览器刷新/关闭、路由跳转(比如进入详情页) window.addEventListener('beforeunload', saveScrollPos); router.events.on('routeChangeStart', saveScrollPos); return () => { window.removeEventListener('beforeunload', saveScrollPos); router.events.off('routeChangeStart', saveScrollPos); }; }, [pathname, router]); // 页面挂载时恢复滚动位置 useEffect(() => { const savedPos = sessionStorage.getItem(`scroll_pos_${pathname}`); if (savedPos) { window.scrollTo(0, parseInt(savedPos, 10)); } }, [pathname]); // 你的无限滚动逻辑 return <div>...</div>; }
保留已加载数据
不推荐用Cookies:Cookies最大容量仅4KB,无限滚动的数据很快会超出限制,且每次HTTP请求都会携带Cookies,浪费带宽。更合理的方案是用sessionStorage存储已加载条目:
'use client'; import { useState, useEffect } from 'react'; import { loadMoreItems } from '@/actions'; // 你的Server Action export default function InfiniteScrollList() { const [items, setItems] = useState([]); const [currentPage, setCurrentPage] = useState(1); // 页面挂载时恢复已保存的数据和页码 useEffect(() => { const savedItems = sessionStorage.getItem('infinite_scroll_items'); const savedPage = sessionStorage.getItem('infinite_scroll_page'); if (savedItems) { setItems(JSON.parse(savedItems)); setCurrentPage(parseInt(savedPage) || 1); } }, []); // 数据更新时同步保存到sessionStorage useEffect(() => { sessionStorage.setItem('infinite_scroll_items', JSON.stringify(items)); sessionStorage.setItem('infinite_scroll_page', currentPage.toString()); }, [items, currentPage]); // 调用Server Action加载更多数据 const loadMore = async () => { const newItems = await loadMoreItems(currentPage); setItems(prev => [...prev, ...newItems]); setCurrentPage(prev => prev + 1); }; // 无限滚动触发逻辑(Intersection Observer示例) useEffect(() => { const loader = document.getElementById('load-more-trigger'); if (!loader) return; const observer = new IntersectionObserver(entries => { if (entries[0].isIntersecting) loadMore(); }); observer.observe(loader); return () => observer.disconnect(); }, [currentPage]); return ( <div className="list-container"> {items.map(item => ( <div key={item.id} className="list-item">{item.content}</div> ))} <div id="load-more-trigger" className="loader">加载中...</div> </div> ); }
额外注意事项
- 数据清理:
sessionStorage会在用户关闭标签页后自动清除数据;如果需要手动清理,可在特定操作(如登出)时调用sessionStorage.removeItem('infinite_scroll_items')。 - 数据一致性:若Server返回的数据可能更新,可在页面挂载时对比数据的最新更新时间,必要时重新拉取初始数据,避免展示过期内容。
- Pages Router适配:如果使用Pages Router,
useRouter需从next/router导入,路由事件监听逻辑保持一致。
内容的提问来源于stack exchange,提问作者moshicode
相关产品推荐
相关产品推荐

