Skip to content

性能

SWR 在各种 web 应用中提供了关键功能,因此性能是重中之重。

SWR 内置的缓存重复数据删除会跳过不必要的网络请求,但 useSWR hook 本身的性能仍然很重要。在一个复杂的应用中,单个页面渲染可能会调用数百个 useSWR

SWR 确保你的应用具有:

  • 没有不必要的请求
  • 没有不必要的重新渲染
  • 没有不必要的代码导入

无需你更改任何代码。

Deduplication(重复数据删除)

在应用中重用 SWR hooks 非常常见。例如,一个应用渲染5次当前用户的头像:

function useUser () {
return useSWR('/api/user', fetcher)
}
function Avatar () {
const { data, error } = useUser()
if (error) return <Error />
if (!data) return <Spinner />
return <img src={data.avatar_url} />
}
function App () {
return <>
<Avatar />
<Avatar />
<Avatar />
<Avatar />
<Avatar />
</>
}

每个 <Avatar> 组件内部都有一个 useSWR hook。由于它们具有相同的 SWR key,并且几乎同时渲染,因此只会发送1个网络请求

你可以在任何地方重用数据 hooks(比如上面示例中的 useUser),而不用担心性能或重复请求。

还有一个 dedupingInterval 选项 用于覆盖默认的重复数据删除间隔。

Deep Comparison(深度比较)

SWR 默认深度比较数据更改。如果 data 值没有改变,则不会触发重新渲染。

如果你还想更改的话,可以通过 compare 选项自定义比较函数。比如,某些 API 响应返回一个服务器时间戳,你可能想从数据 diff 中排除它。

Dependency Collection(依赖收集)

useSWR 返回3个有状态的值:dataerrorisValidating,每个都可以独立更新。例如,如果我们在一个完整的数据请求生命周期中打印这些值,则将如下所示:

function App () {
const { data, error, isValidating } = useSWR('/api', fetcher)
console.log(data, error, isValidating)
return null
}

在最坏的情况下(第一个请求失败,然后重试成功),你将看到5行日志:

// console.log(data, error, isValidating)
undefined undefined false // => hydration / 初始渲染
undefined undefined true // => 开始 fetching
undefined Error false // => 结束 fetching,出现错误
undefined Error true // => 开始重试
Data undefined false // => 重试结束,得到数据

状态的改变是有道理的。但这也意味着组件渲染了5次

如果我们将组件更改为只使用 data

function App () {
const { data } = useSWR('/api', fetcher)
console.log(data)
return null
}

神奇的事情发生了 - 现在只有2次重新渲染

// console.log(data)
undefined // => hydration / 初始渲染
Data // => 重试结束,得到数据

内部发生了完全相同的过程,第一个请求出现了错误,然后我们重试得到了数据。但是,SWR 只更新了组件使用的状态,即:data

如果你不是总使用这3种状态,那么你已经从这个特性中获益了。在 Vercel,这个优化减少了约60%的重新渲染。

Tree Shaking

SWR 是 tree-shakeable 且没有副作用。这意味着如果你只导入核心的 useSWR API,像 useSWRInfinite 这样的未使用的 API 将不会绑定到你的应用中。