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

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

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

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

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

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

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

Хуки SWR зачастую используются в приложении повторно. Например, приложение,
которое рендерит аватар текущего пользователя 5 раз:

```jsx
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`](/docs/options) для переопределения
интервала дедупликации по умолчанию.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Если вы не всегда используете все эти 3 состояния, вы уже извлекаете пользу из
этого функционала. В [Vercel](https://vercel.com) эта оптимизация приводит к
сокращению повторного рендеринга примерно на 60%.

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

Пакет SWR легко [встряхивается](https://webpack.js.org/guides/tree-shaking) и не
имеет побочных эффектов (side-effects). Это означает, что если вы импортируете
только основной API `useSWR`, неиспользуемые API, такие как `useSWRInfinite`, не
будут включены в ваше приложение.
