Next.js 13服务端组件:不使用fetch如何设置为非静态?
问题根源
Next.js 13 App Router的Server Component默认会静态渲染:如果组件中没有使用Next.js扩展的fetch(带缓存控制参数)、noStore或其他动态标识,Next.js会在构建时预渲染组件内容并缓存,导致你的getContributions请求要么只在构建时执行一次,要么因为静态缓存机制无法获取实时数据,甚至请求逻辑被异常处理。
你添加带{cache: 'no-store'}的fetch后,Next.js识别到组件需要动态渲染,所以每次请求都会重新执行组件,API返回值也正常了——本质是这个fetch告诉Next.js:“这个组件不能静态缓存”。
不用fetch的解决方案
方案1:使用noStore标记组件为动态
Next.js 13.4+提供了noStore函数(从next/cache导入),调用它可以直接标记当前Server Component为动态渲染,禁用静态缓存。
修改后的组件代码:
import getContributions from "@/services/github/getContrubutions"; import { noStore } from 'next/cache'; const Contributions = async () => { // 标记组件为动态,禁用静态缓存 noStore(); const contributions = await getContributions(); await new Promise(r => setTimeout(r, 4000)); return ( <> {JSON.stringify({ 'c': 'd', contributions, time: new Date() })} </> ); } export default Contributions;
方案2:组件级配置dynamic属性
直接在组件文件中导出dynamic常量,强制组件动态渲染。这是更声明式的方式,无需在组件内部调用函数。
修改后的组件代码:
import getContributions from "@/services/github/getContrubutions"; // 强制组件每次请求都动态渲染,禁用静态缓存 export const dynamic = 'force-dynamic'; const Contributions = async () => { const contributions = await getContributions(); await new Promise(r => setTimeout(r, 4000)); return ( <> {JSON.stringify({ 'c': 'd', contributions, time: new Date() })} </> ); } export default Contributions;
方案3:给graphql-request的请求添加缓存控制(如果适用)
如果你使用的graphql-request底层基于fetch实现,可以手动给请求添加cache选项,让Next.js识别到这是动态请求。
修改getContributions函数示例:
// @/services/github/getContrubutions.js import { request } from 'graphql-request'; export default async function getContributions() { const endpoint = 'https://api.github.com/graphql'; const query = ` # 你的GraphQL查询语句 `; // 手动设置fetch选项,添加缓存控制 return request(endpoint, query, {}, { cache: 'no-store', // 告诉Next.js这个请求不缓存,触发动态渲染 headers: { Authorization: `Bearer ${process.env.GITHUB_TOKEN}`, }, }); }
这种方法不需要修改组件代码,直接在请求层标记动态特性。
验证效果
以上三种方法都能让Next.js将Contributions组件识别为动态Server Component,每次用户请求时都会重新执行组件逻辑,getContributions的返回值也能正常获取,同时不需要依赖额外的fetch请求。
内容的提问来源于stack exchange,提问作者Francisco Ossian

