Skip to content
开发文档
高级
性能

性能

¥Performance

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

¥SWR provides critical functionality in all kinds of web apps, so performance is a top priority.

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

¥SWR’s built-in caching and deduplication skips unnecessary network requests, but the performance of the useSWR hook itself still matters. In a complex app, there could be hundreds of useSWR calls in a single page render.

SWR 确保你的应用具有:

¥SWR ensures that your app has:

  • 没有不必要的请求

    ¥no unnecessary requests

  • 没有不必要的重新渲染

    ¥no unnecessary re-renders

  • 没有导入不必要的代码

    ¥no unnecessary code imported

你无需更改任何代码。

¥without any code changes from you.

数据去重

¥Deduplication

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

¥It’s very common to reuse SWR hooks in your app. For example, an app that renders the current user’s avatar 5 times:

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 钩子。由于它们具有相同的 SWR key 并且几乎同时渲染,因此只会发出 1 个网络请求。

¥Each <Avatar> component has a useSWR hook inside. Since they have the same SWR key and are rendered almost at the same time, only 1 network request will be made.

你可以在任何地方重复使用数据钩子(如上例中的 useUser),而无需担心性能或重复请求。

¥You can reuse your data hooks (like useUser in the example above) everywhere, without worrying about performance or duplicated requests.

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

¥There is also a dedupingInterval option for overriding the default deduplication interval.

深度比较

¥Deep Comparison

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

¥SWR deep compares data changes by default. If the data value isn’t changed, a re-render will not be triggered.

如果你想更改行为,你还可以通过 compare 选项 自定义比较功能。例如,某些 API 响应返回你可能希望从数据差异中排除的服务器时间戳。

¥You can also customize the comparison function via the compare option if you want to change the behavior. For example, some API responses return a server timestamp that you might want to exclude from the data diff.

依赖集合

¥Dependency Collection

useSWR 返回 4 个状态值:dataerrorisLoadingisValidating,每一个都可以独立更新。例如,如果我们在完整的数据请求生命周期内打印这些值,它将是这样的:

¥useSWR returns 4 stateful values: data, error, isLoading and isValidating, each one can be updated independently. For example, if we print those values within a full data-fetching lifecycle, it will be something like this:

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

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

¥In the worst case (the first request failed, then the retry was successful), you will see 4 lines of logs:

// console.log(data, error, isLoading, isValidating)
undefined undefined true true  // => start fetching
undefined Error false false    // => end fetching, got an error
undefined Error true true      // => start retrying
Data undefined false false     // => end retrying, get the data

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

¥The state changes make sense. But that also means our component rendered 4 times.

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

¥If we change our component to only use data:

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

奇迹发生了 - 现在只有 2 次重新渲染:

¥The magic happens — there are only 2 re-renders now:

// console.log(data)
undefined // => hydration / initial render
Data      // => end retrying, get the data

内部发生了完全相同的过程,第一次请求出现错误,然后我们通过重试获取了数据。但是,SWR 仅更新组件使用的状态,现在仅为 data

¥The exact same process has happened internally, there was an error from the first request, then we got the data from the retry. However, SWR only updates the states that are used by the component, which is only data now.

如果你并不总是使用所有这 3 种状态,那么你已经从该功能中受益。在 Vercel (opens in a new tab),这种优化导致重新渲染次数减少约 60%。

¥If you are not always using all these 3 states, you are already benefitting from this feature. At Vercel (opens in a new tab), this optimization results in ~60% fewer re-renders.

摇树优化

¥Tree Shaking

SWR 包是 tree-shakeable (opens in a new tab) 并且无副作用。这意味着,如果你仅导入核心 useSWR API,则像 useSWRInfinite 这样未使用的 API 将不会打包在你的应用中。

¥The SWR package is tree-shakeable (opens in a new tab) and side-effect free. That means if you are only importing the core useSWR API, unused APIs like useSWRInfinite won't be bundled in your application.