Skip to content
Документация
Начало работы

Начало работы

Установка

Внутри директории вашего React-проекта, выполните команду:

pnpm add swr

Быстрый старт

Для обычных RESTful API с данными JSON сначала необходимо создать функцию fetcher, которая является просто оболочкой для нативного fetch:

const fetcher = (...args) => fetch(...args).then(res => res.json())
💡

Если вы хотите использовать GraphQL API или библиотеки, такие как Axios, вы можете создать свою собственную fetcher-функцию. Смотрите примеры здесь.

Затем можете импортировать useSWR и использовать его внутри функциональных компонентов:

import useSWR from 'swr'
 
function Profile () {
  const { data, error, isLoading } = useSWR('/api/user/123', fetcher)
 
  if (error) return <div>ошибка загрузки</div>
  if (isLoading) return <div>загрузка...</div>
 
  // рендер данных
  return <div>привет, {data.name}!</div>
}

Обычно существует 3 возможных состояния запроса: «загрузка», «готово» или «ошибка». Вы можете использовать значение data, error и isLoading, чтобы определить текущее состояние запроса и вернуть соответствующий UI.

Делайте многоразовыми

При создании веб-приложения вам может потребоваться повторно использовать данные во многих местах пользовательского интерфейса. Создавать многоразовые хуки данных поверх SWR невероятно просто:

function useUser (id) {
  const { data, error, isLoading } = useSWR(`/api/user/${id}`, fetcher)
 
  return {
    user: data,
    isLoading,
    isError: error
  }
}

И используйте их в своих компонентах:

function Avatar ({ id }) {
  const { user, isLoading, isError } = useUser(id)
 
  if (isLoading) return <Spinner />
  if (isError) return <Error />
  return <img src={user.avatar} />
}

Используя этот шаблон, вы можете забыть об императивном получении данных: отправить запрос, обновить состояние загрузки и вернуть окончательный результат. Вместо этого ваш код более декларативен: вам просто нужно указать, какие данные используются компонентом.

Пример

В реальном примере наш веб-сайт показывает панель навигации и контент, оба зависят от user:

Традиционно мы получаем данные один раз, используя useEffect в компоненте верхнего уровня, и передаем их дочерним компонентам через пропсы (обратите внимание, что мы пока не обрабатываем состояние ошибки):

// компонент страницы
 
function Page () {
  const [user, setUser] = useState(null)
 
  // выборка данных
  useEffect(() => {
    fetch('/api/user')
      .then(res => res.json())
      .then(data => setUser(data))
  }, [])
 
  // глобальное состояние загрузки
  if (!user) return <Spinner/>
 
  return <div>
    <Navbar user={user} />
    <Content user={user} />
  </div>
}
 
// дочерний компонент
 
function Navbar ({ user }) {
  return <div>
    ...
    <Avatar user={user} />
  </div>
}
 
function Content ({ user }) {
  return <h1>С возвращением, {user.name}</h1>
}
 
function Avatar ({ user }) {
  return <img src={user.avatar} alt={user.name} />
}

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

Хотя мы можем избежать передачи пропсов с помощью Контекста (opens in a new tab), всё ещё существует проблема с динамическим контентом: компоненты внутри контента страницы могут быть динамическими, и компонент верхнего уровня может не знать, какие данные потребуются его дочерним компонентам.

SWR отлично решает проблему. С помощью только что созданного хука useUser код можно реорганизовать так:

// компонент страницы
 
function Page () {
  return <div>
    <Navbar />
    <Content />
  </div>
}
 
// дочерний компонент
 
function Navbar () {
  return <div>
    ...
    <Avatar />
  </div>
}
 
function Content () {
  const { user, isLoading } = useUser()
  if (isLoading) return <Spinner />
  return <h1>С возвращением, {user.name}</h1>
}
 
function Avatar () {
  const { user, isLoading } = useUser()
  if (isLoading) return <Spinner />
  return <img src={user.avatar} alt={user.name} />
}

Теперь данные привязаны к компонентам, которым нужны данные, и все компоненты независимы друг от друга. Всем родительским компонентам не нужно ничего знать о данных или об их передаче. Они просто рендерят. Код стал намного проще и легче в обслуживании.

Самым прекрасным является то, что в API будет отправлен всего 1 запрос, потому что они используют один и тот же ключ SWR, а запрос автоматически выводится, кешируется и распределяется.

Кроме того, приложение теперь имеет возможность обновлять данные при фокусе или переподключении к сети! Это означает, что когда ноутбук пользователя выходит из спящего режима или он переключается между вкладками браузера, данные обновляются автоматически.