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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 20:13:14