Next.js 13.4.4:首页加载时意外触发详情页API请求问题
Next.js 13.4.4 首页意外触发详情页API请求问题
项目情况
- 使用Next.js 13.4.4版本开发
- 路由结构:
app/ ├── page.tsx(首页) └── details/ └── [id]/ └── page.tsx(详情页)
首页(app/page.tsx)代码
const HomePage = async () => { const games = await getGames(); return ( <div className='container mx-auto px-4 py-8 flex flex-wrap relative z-0'> {games.results.map((game: any) => ( <Link href={`details/${game.id}`} key={game.id}> <div className='w-1/2 sm:w-1/2 md:w-1/3 lg:w-1/5 flex flex-col items-center mb-6'> <div className='w-48 h-64 relative'> <Image src={game.background_image} alt={game.name} width={200} height={300} /> <h2 className='text-center mt-2'>{game.name}</h2> </div> </div> </Link> ))} </div> ); }; export default HomePage;
详情页(app/details/[id]/page.tsx)代码
import Image from 'next/image'; import { getGameDetails } from '@/services'; const GameDetails = async ({ params }: any) => { const game = await getGameDetails(params.id); return ( <div className='container mx-auto px-4 py-8'> <h1 className='text-3xl font-bold mb-4'>{game.name}</h1> <div className='flex flex-col md:flex-row'> <div className='md:w-1/3'> <div className='w-full h-96 relative'> <Image src={game.background_image} alt={game.name} fill className='cover' /> </div> </div> <div className='md:w-2/3 md:pl-8'> <p className='mb-4'>{game.description}</p> <div className='flex flex-wrap items-center mb-4'> <p className='mr-2'>Metacritic Score:</p> {game.metacritic_platforms.map( (platform: { url: string; platform: { name: string; url: string }; metascore: string; }) => ( <a key={platform.platform.url} href={platform.url} target='_blank' rel='noopener noreferrer' className='px-2 py-1 bg-gray-200 text-gray-800 rounded-full mr-2' > {platform.platform.name}: {platform.metascore} </a> ) )} </div> <p className='mb-4'> Released: {new Date(game.released).toLocaleDateString()} </p> <p className='mb-4'>Rating: {game.rating}/5</p> <p className='mb-4'>Genres:</p> <div className='flex flex-wrap mb-4'> {game.genres.map((genre: any) => ( <span key={genre.id} className='px-2 py-1 bg-gray-200 text-gray-800 rounded-full mr-2 mb-2' > {genre.name} </span> ))} </div> <a href={game.website} target='_blank' rel='noopener noreferrer' className='inline-block px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600' > Visit Website </a> </div> </div> </div> ); }; export default GameDetails;
问题
访问首页app/page.tsx时,本应仅在详情页执行的getGameDetails请求也被触发了。
原因
Next.js 13 App Router中的<Link>组件默认开启了**预抓取(prefetch)**功能:页面加载完成后,Next.js会自动预抓取所有可见Link指向的页面内容,包括执行详情页异步组件中的getGameDetails请求,以此提升页面切换速度。
解决方案
方案1:关闭指定Link的预抓取
给首页的<Link>组件添加prefetch={false}属性,阻止预抓取详情页:
<Link href={`details/${game.id}`} key={game.id} prefetch={false}> {/* 原内容 */} </Link>
方案2:仅在hover时预抓取
如果希望保留预抓取但仅在用户hover链接时触发,可以设置prefetch="hover":
<Link href={`details/${game.id}`} key={game.id} prefetch="hover"> {/* 原内容 */} </Link>
方案3:给API请求添加缓存策略
在getGameDetails函数中使用Next.js的fetch缓存机制,即使预抓取触发了请求,后续用户进入详情页时会复用缓存结果,避免重复调用API:
// @/services中的getGameDetails示例 export async function getGameDetails(id: string) { const res = await fetch(`https://your-api-url/games/${id}`, { next: { revalidate: 3600, // 1小时后重新验证缓存 }, }); return res.json(); }
内容的提问来源于stack exchange,提问作者Andon Mitev
相关产品推荐
相关产品推荐

