Skip to content
Документация
Продвинутые
Производительность

Производительность

SWR обеспечивает критически важную функциональность во всех видах веб-приложений, поэтому производительность является главным приоритетом.

Встроенное кеширование и дедупликация SWR пропускают ненужные сетевые запросы, но производительность самого хука useSWR всё ещё имеет значение. В сложном приложении могут быть сотни вызовов useSWR при отрисовке одной страницы.

SWR гарантирует, что в вашем приложении:

  • нет лишних запросов
  • нет лишних повторных рендеров
  • не импортируется ненужный код

без каких-либо изменений кода с вашей стороны.

Дедупликация

Хуки SWR зачастую используются в приложении повторно. Например, приложение, которое рендерит аватар текущего пользователя 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. Поскольку они имеют одинаковый ключ SWR и рендерятся почти одновременно, будет выполнен только 1 сетевой запрос.

Вы можете повторно использовать свои хуки данных (например, useUser в приведенном выше примере) повсюду, не беспокоясь о производительности или дублировании запросов.

Существует также опция dedupingInterval для переопределения интервала дедупликации по умолчанию.

Глубокое сравнение

SWR глубоко сравнивает изменения данных по умолчанию. Если значение data не изменилось, повторный рендеринг запускаться не будет.

Вы также можете настроить функцию сравнения с помощью опции compare, если хотите изменить поведение. Например, некоторые ответы API возвращают отметку времени сервера, которую вы, возможно, захотите исключить из сравнения данных.

Коллекция зависимостей

useSWR возвращает 4 значения с сохранением состояния: data, error, isLoading и isValidating, каждое из которых может обновляться независимо. Например, если мы выведем эти значения внутри полного жизненного цикла выборки данных, это будет примерно так:

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

В худшем случае (первый запрос не удался, затем повторная попытка была успешной) вы увидите 4 строки журнала:

// console.log(data, error, isLoading, isValidating)
undefined undefined true true  // => начало выборки
undefined Error false false    // => конец выборки, получили ошибку
undefined Error true true      // => начало повторной попытки
Data undefined false false     // => конец повторной попытки, получение данных

Изменения состояния имеют смысл. Но это также означает, что наш компонент рендерился 4 раза.

Если мы изменим наш компонент на использование только data:

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

Волшебство происходит — теперь всего 2 рендера:

// console.log(data)
undefined // => гидратация / начальный рендер
Data      // => конец повторной попытки, получение данных

Точно такой же процесс произошёл внутри, возникла ошибка при первом запросе, затем мы получили данные при повторной попытке. Однако SWR обновляет только состояния, используемые компонентом, которым сейчас является только data.

Если вы не всегда используете все эти 3 состояния, вы уже извлекаете пользу из этого функционала. В Vercel (opens in a new tab) эта оптимизация приводит к сокращению повторного рендеринга примерно на 60%.

Встряхивание (Tree Shaking)

Пакет SWR легко встряхивается (opens in a new tab) и не имеет побочных эффектов (side-effects). Это означает, что если вы импортируете только основной API useSWR, неиспользуемые API, такие, как useSWRInfinite, не будут включены в ваше приложение.