SWR 条件数据请求(Conditional Fetching)与依赖请求实战指南
【免费下载链接】nextraSimple, powerful and flexible site generation framework with everything you love from Next.js.项目地址: https://gitcode.com/GitHub_Trending/ne/nextra
导读
本指南基于 nextra 仓库 中 SWR 官方文档站的《Conditional Fetching》章节(源文件位于 examples/swr-site/content/en/docs/conditional-fetching.md),系统讲解 SWR(React Hooks 数据请求库)中"何时发请求、如何按依赖关系发请求"的核心能力:通过把key设为null或函数来暂停请求、按需触发,以及通过函数式key实现"数据依赖数据"的串行/并行请求编排。读完本文,你将掌握条件请求、依赖请求的完整写法、底层判定逻辑,以及它们与 Suspense、全局配置组合时的边界行为。
背景:SWR 的 key 是请求的唯一标识
在 SWR 中,useSWR(key, fetcher)的key不仅是一个字符串,它还是请求的唯一标识与缓存键。官方参数说明见 examples/swr-site/content/en/docs/options.mdx:key可以是一个字符串,也可以是函数、数组或null。正是"函数与null"这两种形态,构成了条件请求与依赖请求的全部基础:
- 当
key是null或函数返回 falsy 值时,请求不会发起,SWR 保持暂停状态; - 当
key是函数时,SWR 会调用该函数,并把返回值当作真正的 key使用。
这意味着"发不发请求"和"请求什么内容"都可以被动态计算,从而把数据获取的主动权完全交给应用逻辑。
一、条件请求(Conditional):用 key 控制是否发起请求
条件请求解决的核心问题是:某些数据只有在特定条件下才应该被拉取(例如用户尚未登录、页面开关未打开、权限未就绪时)。SWR 官方文档给出了三种等价写法,全部继承自 conditional-fetching.md:
// 方式一:直接用三元表达式,条件不满足时 key 为 null const { data } = useSWR(shouldFetch ? '/api/data' : null, fetcher) // 方式二:用函数返回 key,条件不满足时返回 falsy 值 const { data } = useSWR(() => (shouldFetch ? '/api/data' : null), fetcher) // 方式三:让函数抛出异常,例如依赖的对象还未加载完成 const { data } = useSWR(() => '/api/data?uid=' + user.id, fetcher)三种方式的共同判定规则是:如果 key 为null,或作为 key 的函数返回 falsy 值,或函数执行时抛出异常,SWR 就不会发起请求。具体来说:
| 写法 | 触发条件 | 暂停原因 |
|---|---|---|
key = null | shouldFetch为假 | key 为null,无请求 |
key = () => (cond ? url : null) | 函数返回null/undefined/false | 返回值 falsy |
key = () => url + user.id | user尚未加载,访问user.id抛错 | 函数抛出异常 |
第三种写法看似"报错",实则是 SWR 依赖请求机制的核心——通过抛异常来声明"依赖未就绪",从而暂停下游请求。这一点在下一节展开。
从实现角度可以印证:conditional-fetching在 SWR 文档站中被归类为 Conditional Data Fetching,位于"Getting Started"分组中,属于 SWR 基础 API 的进阶用法,其姊妹文档>function MyProjects() { const { data: user } = useSWR('/api/user') const { data: projects } = useSWR(() => '/api/projects?uid=' + user.id) // 传入函数时,SWR 会把函数返回值作为 key。 // 如果函数抛出异常或返回 falsy 值,SWR 就知道某些依赖尚未就绪。 // 这里当 user 未加载时,访问 user.id 会抛异常。 if (!projects) return 'loading...' return 'You have ' + projects.length + ' projects' }
执行流程拆解如下:
- 组件挂载时,
/api/user与/api/projects两个请求会同时(并行)发起,避免串行等待; - 若
/api/user尚未返回,函数() => '/api/projects?uid=' + user.id在执行时因访问undefined.id而抛出异常; - SWR 捕获该异常,暂停
/api/projects的请求,并将其视为"依赖未就绪"; - 一旦
user数据就绪并触发组件重渲染,key 函数再次执行成功,/api/projects随即自动发起; - 页面最终展示
projects.length。
这就是官方文档所述"在避免瀑布的同时保证最大并行度":数据就绪的部分先并行拉取,存在依赖的部分自动退化为串行。这也是函数式 key 相比手动await的核心优势——你不需要自己编写"等 user 到了再请求 projects"的协调逻辑,SWR 基于异常/ falsy 的约定替你完成了调度。
与 Suspense 组合时的注意点
当suspense: true开启时,SWR 通常保证渲染时data一定存在;但与条件请求或依赖请求组合时,如果请求处于**暂停(paused)**状态,data依然可能是undefined。官方在 suspense.mdx 中明确给出了此限制:
function Profile() { const { data } = useSWR(isReady ? '/api/user' : null, fetcher, { suspense: true }) // 当 isReady 为 false 时,data 仍是 undefined }因此在 Suspense + 条件请求的组合下,渲染逻辑仍需对data做空值兜底,不能依赖 Suspense 的"数据必然就绪"保证。
三、实践:把条件请求接入全局配置与数据预填
条件请求通常不是孤立使用的,它与 SWR 的全局配置体系天然互补。以本仓库的 swr-site 示例站点为例(examples/swr-site/package.json),它通过nextra与nextra-theme-docs搭建多语言文档站,文档正文以 MDX 存放在 examples/swr-site/content/en/docs 下,其中条件请求文档还提供了完整的西班牙语译本 conditional-fetching.md(es),说明该能力是 SWR 官方文档体系中的标准章节。
用 SWRConfig 统一 fetcher 与刷新策略
虽然条件请求管的是"何时发",但"怎么发"通常交给全局配置。官方 global-configuration.md 展示了通过<SWRConfig>为所有 SWR hook 提供默认 fetcher 与轮询间隔:
import useSWR, { SWRConfig } from 'swr' function Dashboard() { const { data: events } = useSWR('/api/events') const { data: projects } = useSWR('/api/projects') const { data: user } = useSWR('/api/user', { refreshInterval: 0 }) // 覆盖全局配置 } function App() { return ( <SWRConfig value={{ refreshInterval: 3000, fetcher: (resource, init) => fetch(resource, init).then(res => res.json()) }} > <Dashboard /> </SWRConfig> ) }当全局 fetcher 提供后,条件请求的useSWR(shouldFetch ? '/api/data' : null)甚至可以省略 fetcher 参数;同时注意refreshInterval会作用于所有 key——如果某个条件请求暂停,轮询是否继续取决于其 key 函数是否仍返回 falsy,暂停中的请求不会因轮询而意外发起。
用 fallback 预填数据,配合条件请求实现首屏策略
在 SSG/SSR 场景下,可以在服务端预取数据后通过SWRConfig的fallback注入,客户端useSWR会优先使用预填数据。官方 with-nextjs.mdx 给出了getStaticProps完整示例;结合条件请求,你可以实现"首屏用预填数据渲染,后续按条件增量拉取"的渐进增强模式。
四、从文档站源码看该章节的组织方式
本仓库中该文档的工程落地细节,可以从 swr-site 示例站点的源码结构得到印证:
- 文档路由:
examples/swr-site/app/[lang]/[[...mdxPath]]/page.tsx通过nextra/pages的generateStaticParamsFor('mdxPath')与importPage(params.mdxPath, params.lang)按语言与路径动态加载 MDX 页面,conditional-fetching.md即对应/en/docs/conditional-fetching路由; - 多语言支持:文档内容按
content/{en,es,ru}/docs分目录存放,语言切换由 app/[lang]/layout.tsx 中的i18n配置驱动(en、es、ru三种语言,其中 es 站点被标注为 RTL 语言,见 next.config.ts); - 导航与目录:条件请求章节在侧边栏中的标题为 "Conditional Data Fetching",由 content/en/docs/_meta.tsx 中的
'conditional-fetching': 'Conditional Data Fetching'声明,排在revalidation(自动重新验证)之后、arguments(多参数 key)之前,与相邻章节共同构成完整的 SWR 数据获取知识体系; - 配套章节:与条件请求强相关的姊妹文档包括 options.mdx(key 参数定义)、data-fetching.mdx(fetcher 机制)、global-configuration.md(全局配置)、suspense.mdx(Suspense 兼容性)与 mutation.md(数据更新),读者可按需串联阅读。
五、常见问题与排查要点
- 请求一直不发,卡在暂停态:检查 key 函数是否稳定返回 falsy 或持续抛异常。依赖请求场景下,最典型原因是依赖数据接口失败(而非慢),导致
user.id永远无法访问——此时应先排查上游请求的error状态; - 条件请求与轮询冲突:全局
refreshInterval只对"已激活"的 key 生效,暂停中的 key 不会被轮询唤醒;若希望条件满足后立即刷新,可配合 mutation.md 中的mutate(key)手动触发重新验证; - 渲染时空值处理:暂停态下
data为undefined,渲染必须做空值兜底(如if (!projects) return 'loading...');Suspense 模式下暂停态同样可能返回undefined,不能想当然地省略判空; - key 函数必须是纯函数:key 函数应只依赖组件状态与已有数据,避免内部产生副作用或使用不稳定随机值,否则会导致 key 在每次渲染间变化,触发不必要的重复请求。
小结
条件请求与依赖请求是 SWR 将"请求调度"抽象进 hook 的经典设计:null/falsy/异常三种暂停信号统一了"条件不满足"的表达,函数式 key 则在保持并行度的同时天然实现了依赖排序。本文所有示例与结论均可追溯至仓库内的 conditional-fetching.md 原文及其配套源码,读者可直接在 swr-site 示例中替换为自己的接口路径进行验证。
【免费下载链接】nextraSimple, powerful and flexible site generation framework with everything you love from Next.js.项目地址: https://gitcode.com/GitHub_Trending/ne/nextra
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考