在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地址请求数据并更新列表:
- 用
useState管理文章列表、下一页地址和加载状态 - 编写异步函数请求下一页数据,合并到现有列表
- 渲染下一页按钮并绑定点击事件
修改后的组件代码:
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
相关产品推荐
相关产品推荐

