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

在Next.js构建的Prismic应用中实现文章分页加载的方法

问题

我用Prismic和Next.js搭建了应用,首页只展示3篇文章,想要实现点击「下一页」按钮加载后续3篇文章。目前首页返回的articles数据里包含next_page字段(下一页文章的API地址),请问怎么利用这个字段或者通过Prismic API/Next.js API实现下一页文章的获取?

数据结构

{
    "page": 1,
    "results_per_page": 3,
    "results_size": 3,
    "total_results_size": 14,
    "total_pages": 5,
    "next_page": "https://myapp.cdn.prismic.io/api/v2/documents/search?ref=Y-N6RxAAACEAh2Gz&q=%5B%5Bat%28document.type%2C+%22article%22%29%5D%5D&orderings=%5Bmy.article.publishDate+desc%2Cdocument.first_publication_date+desc%5D&page=2&pageSize=3",
    "prev_page": null,
    "results": [
        {"title": "result 1"},
        {"title": "result 2"},
        {"title": "result 3"}
    ],
    "license": "All Rights Reserved"
}

当前代码

const Index = ({ articles, navigation, settings, pathname }) => {
  
  return (
    <Layout>
      <Bounded size="widest">
        <ul className="grid grid-cols-1 gap-16">
          {articles?.results.map((article) => (
            <Article key={article.id} article={article} />
          ))}
        </ul>
        <NextLink href={articles.next_page}>test</NextLink>
      </Bounded>
    </Layout>
  );
};

export default Index;

export async function getStaticProps({ previewData }) {
  const client = createClient({ previewData });

  const articles = await client.getByType("article", {
    orderings: [
      { field: "my.article.publishDate", direction: "desc" },
      { field: "document.first_publication_date", direction: "desc" },
    ],
    pageSize: 3,
  });
  const navigation = await client.getSingle("navigation");
  const settings = await client.getSingle("settings");
  console.log(articles);
  return {
    props: {
      articles,
      navigation,
      settings,
    },
  };
}

解决方案

方案一:前端动态加载(无页面跳转)

适合不需要URL变化的场景,直接在当前页通过next_page地址请求数据并更新列表:

  1. 用useState管理文章列表、下一页地址和加载状态
  2. 编写异步函数请求下一页数据,合并到现有列表
  3. 渲染下一页按钮并绑定点击事件

修改后的组件代码:

import { useState } from 'react';
import Layout from '../components/Layout';
import Bounded from '../components/Bounded';
import Article from '../components/Article';

const Index = ({ initialArticles, navigation, settings }) => {
  const [articles, setArticles] = useState(initialArticles.results);
  const [nextPageUrl, setNextPageUrl] = useState(initialArticles.next_page);
  const [isLoading, setIsLoading] = useState(false);

  const fetchNextPage = async () => {
    if (!nextPageUrl || isLoading) return;
    setIsLoading(true);
    try {
      const res = await fetch(nextPageUrl);
      const nextPageData = await res.json();
      // 合并新文章到现有列表
      setArticles(prev => [...prev, ...nextPageData.results]);
      // 更新下一页地址
      setNextPageUrl(nextPageData.next_page);
    } catch (err) {
      console.error('加载下一页失败:', err);
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <Layout>
      <Bounded size="widest">
        <ul className="grid grid-cols-1 gap-16">
          {articles.map((article) => (
            <Article key={article.id} article={article} />
          ))}
        </ul>
        {nextPageUrl && (
          <button 
            onClick={fetchNextPage} 
            disabled={isLoading}
            className="mt-8 px-4 py-2 bg-blue-500 text-white rounded"
          >
            {isLoading ? '加载中...' : '下一页'}
          </button>
        )}
      </Bounded>
    </Layout>
  );
};

export default Index;

export async function getStaticProps({ previewData }) {
  const client = createClient({ previewData });

  const initialArticles = await client.getByType("article", {
    orderings: [
      { field: "my.article.publishDate", direction: "desc" },
      { field: "document.first_publication_date", direction: "desc" },
    ],
    pageSize: 3,
  });
  const navigation = await client.getSingle("navigation");
  const settings = await client.getSingle("settings");

  return {
    props: {
      initialArticles,
      navigation,
      settings,
    },
  };
}

方案二:URL同步分页(带页面跳转)

如果需要URL显示当前页码(比如/?page=2),可以用Next.js的查询参数结合Prismic客户端的page参数实现:

1. 修改组件的下一页链接

import Link from 'next/link';

// 在Index组件中替换原有的NextLink
{articles.next_page && (
  <Link href={`/?page=${articles.page + 1}`} passHref>
    <a className="mt-8 inline-block px-4 py-2 bg-blue-500 text-white rounded">
      下一页
    </a>
  </Link>
)}

2. 在getStaticProps中接收页码参数并请求对应页数据

export async function getStaticProps({ previewData, query }) {
  const client = createClient({ previewData });
  // 默认显示第1页
  const currentPage = parseInt(query.page) || 1;

  const articles = await client.getByType("article", {
    orderings: [
      { field: "my.article.publishDate", direction: "desc" },
      { field: "document.first_publication_date", direction: "desc" },
    ],
    pageSize: 3,
    page: currentPage, // 传递当前页参数
  });
  const navigation = await client.getSingle("navigation");
  const settings = await client.getSingle("settings");

  return {
    props: {
      articles,
      navigation,
      settings,
    },
    // 开启增量静态再生,页面内容自动更新
    revalidate: 60,
  };
}

可选:预生成所有分页页面

如果总页数固定,用getStaticPaths预生成所有分页页面,提升访问速度:

export async function getStaticPaths() {
  const client = createClient();
  // 先获取总页数
  const totalPages = await client.getByType("article", { pageSize: 3 }).then(res => res.total_pages);
  
  // 生成所有分页路径
  const paths = Array.from({ length: totalPages }, (_, i) => ({
    params: { page: (i + 1).toString() },
  }));

  return {
    paths,
    fallback: false,
  };
}

方案三:直接用Prismic客户端的page参数(替代next_page)

其实不需要直接调用next_page的CDN URL,Prismic客户端支持通过page参数直接请求对应页的数据,逻辑和首页完全一致,只需修改page值即可。比如请求第2页:

const articles = await client.getByType("article", {
  orderings: [/* 排序规则 */],
  pageSize: 3,
  page: 2, // 指定页码
});

这种方式更符合Next.js服务端渲染的逻辑,避免跨域和直接调用外部API的问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 00:25:23