将 SWR React Hooks 与 Next.js 的增量静态再生 (ISR) 结合使用

已发表: 2022-03-10
快速总结 ↬当与 ISR 和 Next.js 的 API 路由配合使用时,SWR 可用于创建响应式用户体验。 在本文中,Sam Poder 解释了 SWR 是什么,在哪里使用(以及在哪里不使用),以及如何使用增量静态再生来构建网站。

如果您曾经在 Next.js 中使用过增量静态再生 (ISR),您可能会发现自己正在向客户端发送陈旧的数据。 当您在服务器上重新验证页面时会发生这种情况。 对于某些网站,这是可行的,但对于其他网站(例如 Hack Club 的 Scrapbook,我帮助维护的由 @lachlanjc 构建的网站),用户希望数据保持最新。

想到的第一个解决方案可能是简单地在服务器端呈现页面,确保始终向客户端发送最新数据。 但是,在渲染之前获取大量数据会减慢初始页面加载速度。 Scrapbook 中使用的解决方案是使用 React 挂钩的 SWR 库通过客户端数据获取从服务器更新缓存页面。 这种方法可确保用户仍然拥有良好的体验、站点速度快并且数据保持最新。

认识 SWR

SWR 是由 Vercel 构建的 React Hooks 库,名称来自术语 stale-while-revalidate。 顾名思义,在客户端通过 SWR 获取(重新验证)最新数据时,将为您的客户端提供陈旧/旧数据。 然而,SWR不只是重新验证数据一次,您可以将SWR配置为在标签重新恢复对焦时重新验证数据,当客户端重新连接到Internet或以编程方式进行焦点时。

当与 ISR 和 Next.js 的 API 路由配合使用时,SWR 可用于创建响应式用户体验。 首先为客户端提供缓存的静态生成页面(使用getStaticProps()生成),在后台服务器也开始重新验证该页面的过程(在此处阅读更多内容)。 这个过程对客户来说感觉很快,他们现在可以看到数据集,但是它可能有点过时了。 页面加载后,将向您的 Next.js API 路由发出获取请求,该路由返回与使用getStaticProps()生成的数据相同的数据。 当这个请求完成时(假设它成功),SWR 将用这个新数据更新页面。

现在让我们回顾一下 Scrapbook 以及它如何帮助解决页面上存在陈旧数据的问题。 显而易见的是,现在,客户端获得了更新版本。 然而,更有趣的是对我们这边的速度的影响。 当我们通过 Lighthouse 测量速度时,我们得到站点的 ISR + SWR 变体的速度指数为1.5 秒,服务器端渲染变体的速度指数为5.8 秒(加上有关初始服务器响应时间的警告)。 这两者之间形成了鲜明的对比(在加载页面时也很明显)。 但也有一个权衡,在服务器端渲染页面上,用户在几秒钟后没有更改站点布局,新数据进入。虽然我相信 Scrapbook 可以很好地处理这个更新,但这是一个重要的考虑因素设计您的用户体验。

跳跃后更多! 继续往下看↓

在哪里使用 SWR(以及在哪里不使用)

SWR 可以放置在各种地方,以下是 SWR 非常适合的几个站点类别:

  • 具有需要快速更新的实时数据的站点。
    此类站点的示例是体育比分站点和航班跟踪。 在构建这些站点时,您希望使用间隔设置较低(1 到 5 秒)的 revalidate on interval 选项。
  • 具有实时更新的更新或帖子的提要样式的站点。
    典型的例子是新闻网站,这些网站有关于选举等事件的实时博客。 另一个例子也是前面提到的剪贴簿。 在这种情况下,您可能还希望使用 revalidate on interval 选项,但使用更高的间隔设置(30 到 60 秒)来节省数据使用量并防止不必要的 API 调用。
  • 具有更多被动数据更新的站点,人们经常在后台保持打开状态。
    这些站点的示例是天气页面或 2020 年代 COVID-19 病例编号页面。 这些页面不会频繁更新,因此不需要对前两个示例进行不断的重新验证。 但是,它仍然会增强数据更新的用户体验。 在这些情况下,我建议重新验证选项卡重新获得焦点的日期以及客户端重新连接到互联网的日期,这意味着如果一个人焦急地返回水龙头,希望 COVID 病例只会有小幅增加,他们会快速获取该数据。
  • 具有用户可以与之交互的小块数据的站点。
    想想 Youtube 订阅按钮,当您单击订阅时,您希望看到计数发生变化并感觉自己有所作为。 在这些情况下,您可以使用 SWR 以编程方式重新验证数据,以获取新计数并更新显示的数量。

需要注意的一件事是,这些都可以在有或没有 ISR 的情况下应用。

当然,有些地方您不想使用 SWR 或在没有 ISR 的情况下使用 SWR。 如果您的数据没有变化或变化很少,SWR 就没有多大用处,反而会阻塞您的网络请求并耗尽移动用户的数据。 SWR 可以处理需要身份验证的页面,但是在这些情况下您将希望使用服务器端渲染而不是增量静态重新生成。

将 SWR 与 Next.js 和增量静态再生一起使用

现在我们已经探索了这种策略的理论,让我们探索我们如何将其付诸实践。 为此,我们将使用政府提供的 API 建立一个网站,显示新加坡(我住的地方!)有多少出租车。

项目结构

我们的项目将通过三个文件来工作:

  • lib/helpers.js
  • pages/index.js (我们的前端文件)
  • pages/api/index.js (我们的 API 文件)

我们的帮助文件将导出一个函数 ( getTaxiData ),该函数将从外部 API 获取数据,然后以适当的格式返回以供我们使用。 我们的 API 文件将导入该函数并将其设置为默认导出到将调用getTaxiData函数然后返回它的处理函数,这意味着向/api发送 GET 请求将返回我们的数据。

我们需要 SWR 的这种能力来进行客户端数据获取。 最后,在我们的前端文件中,我们将导入getTaxiData并在getStaticProps中使用它,它的数据将传递给我们的前端文件的默认导出函数,该函数将呈现我们的 React 页面。 我们这样做是为了防止代码重复并确保数据的一致性。 好拗口,让我们现在开始编程吧。

助手文件

我们将从在lib/helpers.js中创建getTaxiData函数开始:

 export async function getTaxiData(){ let data = await fetch("https://api.data.gov.sg/v1/transport/taxi-availability").then(r => r.json()) return {taxis: data.features.properties[0].taxi_count, updatedAt: data.features.properties[0].timestamp} }

API 文件

然后我们将在api/index.js中构建处理函数并导入getTaxiData函数:

 import { getTaxiData } from '../../lib/helpers' export default async function handler(req, res){ res.status(200).json(await getTaxiData()) }

除了前面提到的项目结构之外,这里没有任何 SWR 或 ISR 独有的东西。 这些东西现在从index.js开始!

前端文件

我们要做的第一件事就是创建我们的getStaticProps函数! 该函数将导入我们的getTaxiData函数,使用它,然后通过一些额外的配置返回数据。

 export async function getStaticProps(){ const { getTaxiData } = require("../lib/helpers") return { props: (await getTaxiData()), revalidate: 1 } }

我想专注于我们返回的对象中的 revalidate 键。 该键实际上启用了增量静态再生。 它告诉您的主机每秒重新生成静态页面是一个可用选项,然后当客户端访问您的页面时,该选项会在后台触发。 您可以在此处阅读有关增量静态再生 (ISR) 的更多信息。

现在是使用 SWR 的时候了! 我们先导入它:

 import useSWR from 'swr'

我们将在我们的 React 渲染函数中使用 SWR,所以让我们创建该函数:

 export default function App(props){ }

我们从getStaticProps接收道具。 现在我们准备好设置 SWR:

 const fetcher = (...args) => fetch(...args).then(res => res.json()) const { data } = useSWR("/api", fetcher, {fallbackData: props, refreshInterval: 30000})

让我们分解一下。 首先,我们定义 fetcher。 这是 SWR 要求的一个参数,以便它知道如何获取您的数据,因为不同的框架等可以有不同的设置。 在这种情况下,我使用的是 SWR 文档页面上提供的功能。 然后我们使用三个参数调用useSWR钩子:从中获取数据的路径、获取器函数和一个选项对象。

在该options对象中,我们指定了两件事:

  1. 后备数据;
  2. SWR 应重新验证数据的时间间隔。

后备数据选项是我们提供从getStaticProps获取的数据的地方,它确保数据从一开始就可见。 最后,我们使用对象解构从钩子中提取数据。

最后,我们将使用一些非常基本的 JSX 渲染这些数据:

 return <div>As of {data.updatedAt}, there are {data.taxis} taxis available in Singapore!</div>

而且,我们做到了! 我们有一个使用 SWR 和增量静态再生的非常简单的示例。 (我们示例的源代码可在此处获得。)

如果您曾经使用 ISR 遇到过时的数据,您知道该联系谁:SWR。

进一步阅读 SmashingMag

  • SWR React Hooks 库
  • SWR 简介:用于远程数据获取的 React Hooks,Ibrahima Ndaw
  • ISR 与 DPR:大词,快速解释,卡西迪·威廉姆斯
  • Next.js 中的全局与本地样式,Alexander Dubovoj
  • Next.js 中的客户端路由,Adebiyi Adedotun Lukman