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

Next.js 14中generateStaticParams无法传数据引发重复API请求问题

关于Next.js generateStaticParams复用数据的问题

我对Next.js中generateStaticParams的工作方式有疑问:通常我们会获取ID来生成路由段,但获取这些ID的API调用其实已经包含了构建所有页面所需的全部数据,却没法把这些额外数据作为props传给页面组件。

就像我的例子,构建时Next.js会为每个页面调用一次ArticleAPI.fetchByCategory,参数来自generateStaticParams,但明明可以复用generateStaticParams里已经拿到的数据?这样1000个路由就要发1000次请求,而不是一次请求搞定所有页面的数据。

代码示例(路径:/articles/categories/[category]/page.ts)

import { ArticleAPI } from "@/api/article-api";
import { ArticleList } from "@/components/ArticleList/ArticleList";
import { Article, ArticleCategory } from "@/types/article-type";

export async function generateStaticParams() {
  const articlesByCat = await ArticleAPI.fetchAllCategories();
  const params = Object.keys(articlesByCat).map((category) => {
    const articles = articlesByCat[category];
    return {
      params: {
        category,
        articles, // 我本以为可以将其传递给组件?
      },
    };
  });

  return params;
}
export default async function ArticlesFilteredByCategories(p: {
  params: { category: ArticleCategory; articles: Article[] };
}) {

  // 但这里p.params只包含category,没有articles...
  // 例如访问/articles/categories/business时,仅得到{ category : "business" }

  // 我希望能从generateStaticParams接收articles作为props
  // 而非在这里再次发起请求(若有100个页面,构建时就要发起100次API请求),而数据其实已在generateStaticParams()中获取到了

  const articles = await ArticleAPI.fetchByCategory(p.params.category);
  return (
    <ArticleList
      articles={articles}
    />
  );
}

解决方案:复用请求结果避免重复调用

你没法直接把generateStaticParams里的额外数据传给页面组件,但可以通过缓存来实现数据复用,避免重复发起API请求。

方法1:模块级缓存

在页面模块内维护一个缓存变量,存储fetchAllCategories的结果,页面组件直接读取缓存:

import { ArticleAPI } from "@/api/article-api";
import { ArticleList } from "@/components/ArticleList/ArticleList";
import { Article, ArticleCategory } from "@/types/article-type";

// 模块级缓存,存储全部分类的文章数据
let cachedArticlesByCat: Record<ArticleCategory, Article[]> | null = null;

export async function generateStaticParams() {
  // 首次请求并缓存数据
  cachedArticlesByCat = await ArticleAPI.fetchAllCategories();
  // 只返回路由需要的category参数
  return Object.keys(cachedArticlesByCat).map(category => ({
    params: { category }
  }));
}

export default async function ArticlesFilteredByCategories(p: {
  params: { category: ArticleCategory };
}) {
  // 优先使用缓存,若缓存不存在则重新请求(应对增量静态再生场景)
  const articlesByCat = cachedArticlesByCat || await ArticleAPI.fetchAllCategories();
  const articles = articlesByCat[p.params.category];
  
  return <ArticleList articles={articles} />;
}

方法2:API层缓存

在API封装层添加缓存逻辑,让所有调用复用同一份请求结果:

// @/api/article-api.ts
let allCategoriesCache: Promise<Record<ArticleCategory, Article[]>> | null = null;

export const ArticleAPI = {
  fetchAllCategories: async () => {
    if (!allCategoriesCache) {
      // 仅在首次调用时发起请求
      allCategoriesCache = fetch('/api/articles/all-categories')
        .then(res => {
          if (!res.ok) throw new Error('请求失败');
          return res.json();
        });
    }
    return allCategoriesCache;
  },
  
  fetchByCategory: async (category: ArticleCategory) => {
    // 复用fetchAllCategories的缓存结果
    const allData = await ArticleAPI.fetchAllCategories();
    return allData[category];
  }
};

这样不管是generateStaticParams还是页面组件调用fetchByCategory,都会复用同一份API请求结果,不会重复发起请求。

为什么不能直接传递额外数据?

generateStaticParams的返回值仅允许包含路由参数(即URL中的动态部分),Next.js不会将额外数据传递给页面组件。这是因为静态生成的页面需要与路由一一对应,额外数据会增加构建产物的复杂度,同时在运行时(如增量静态再生)无法保证数据的一致性。

内容的提问来源于stack exchange,提问作者Topsy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 01:53:16