Использование с Next.js

App Router

Серверные компоненты

В Next.js App Router по умолчанию все компоненты являются React Server Components (RSC). Вы можете импортировать SWRConfig и ключевые API сериализации из SWR в RSC.

import { unstable_serialize } from 'swr' // ✅ Доступно в серверных компонентах
import { unstable_serialize as infinite_unstable_serialize } from 'swr/infinite' // ✅ Доступно в серверных компонентах

import { SWRConfig } from 'swr' // ✅ Доступно в серверных компонентах

Вы не можете импортировать hook API из SWR, так как они не доступны в RSC.

import useSWR from 'swr' // ❌ Недоступно в серверных компонентах
import useSWRInfinite from 'swr/infinite' // ❌ Недоступно в серверных компонентах
import useSWRMutation from 'swr/mutation' // ❌ Недоступно в серверных компонентах

Клиентские компоненты

Вы можете пометить свои компоненты директивой 'use client' или импортировать SWR из клиентских компонентов. Оба способа позволят вам использовать хуки получения данных SWR на стороне клиента.

'use client'

import useSWR from 'swr'

export default function Page() {
  const { data } = useSWR('/api/user', fetcher)
  return <h1>{data.name}</h1>
}

Предварительная выборка данных в серверных компонентах

Подобно паттерну предварительного рендеринга с данными по умолчанию, с React Server Components (RSC) вы можете пойти ещё дальше.

Вы можете инициировать предварительную выборку данных на стороне сервера и передать promise в дерево клиентских компонентов через опцию fallback провайдера <SWRConfig>:

import { SWRConfig } from 'swr'

export default async function Layout({ children }: { children: React.ReactNode }) {
  // Инициируйте выборку данных на стороне сервера.
  const userPromise = fetchUserFromAPI()
  const postsPromise = fetchPostsFromAPI()

  return (
    <SWRConfig
      value={{
        fallback: {
          // Передайте promises клиентским компонентам.
          '/api/user': userPromise,
          '/api/posts': postsPromise,
        },
      }}
    >
      {children}
    </SWRConfig>
  )
}

Два вызова функций выборки данных fetchUserFromAPI() и fetchPostsFromAPI() будут выполнены параллельно на стороне сервера, потому что мы не ожидаем их немедленно.

В React Server Components вы можете передавать promises через границу "use client", и SWR автоматически разрешит их во время рендеринга на стороне сервера:

'use client'

import useSWR from 'swr'

export default function Page() {
  // SWR разрешит promise, переданный из серверных компонентов.
  // И `user`, и `posts` будут готовы во время SSR и гидратации клиента.
  const { data: user } = useSWR('/api/user', fetcher)
  const { data: posts } = useSWR('/api/posts', fetcher)

  return (
    <div>
      <h1>{user.name}'s Posts</h1>
      <ul>
        {posts.map(post => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  )
}

Затем на стороне клиента SWR возьмет на себя управление и сохранит обычное поведение.

Передавая promises из серверных компонентов в клиентские компоненты, выборка данных может быть инициирована как можно раньше на стороне сервера. И только границы пользовательского интерфейса (ближайшая граница Suspense или layout Next.js), которые фактически используют данные, будут заблокированы во время потокового SSR.

Чтобы постепенно внедрять этот паттерн предварительной выборки в вашем приложении, вы можете включить опцию strictServerPrefetchWarning. Это будет отображать предупреждающее сообщение в консоли, когда для ключа не предоставлены предварительно заполненные данные, помогая вам определить, какие вызовы выборки данных могут выиграть от предварительной выборки на стороне сервера.

Получение данных на стороне клиента

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

Вот как это работает:

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

Этот подход хорошо подходит, например, для страниц пользовательских панелей инструментов. Поскольку панель инструментов является частной, пользовательской страницей, SEO не имеет значения, и страницу не нужно предварительно рендерить. Данные на этой странице часто обновляются, что требует запроса данных во время выполнения.

Предварительный рендеринг с данными по умолчанию

Если страница должна быть предварительно отрендерена, Next.js поддерживает 2 формы предварительного рендеринга: Static Generation (SSG) и Server-side Rendering (SSR).

Совместно с SWR вы можете предварительно отрендерить страницу для SEO, а также использовать функции, такие как кэширование, ревалидация, отслеживание фокуса, повторное получение данных через интервал на стороне клиента.

Вы можете использовать параметр fallback в SWRConfig, чтобы передать предварительно полученные данные в качестве начального значения для всех хуков SWR.

Например, с использованием getStaticProps:

 export async function getStaticProps () {
  // `getStaticProps` выполняется на стороне сервера.
  const article = await getArticleFromAPI()
  return {
    props: {
      fallback: {
        '/api/article': article
      }
    }
  }
}

function Article() {
  // `data` всегда будет доступна, так как она находится в `fallback`.
  const { data } = useSWR('/api/article', fetcher)
  return <h1>{data.title}</h1>
}

export default function Page({ fallback }) {
  // Хуки SWR внутри области `SWRConfig` будут использовать эти значения.
  return (
    <SWRConfig value={{ fallback }}>
      <Article />
    </SWRConfig>
  )
}

Страница всё ещё предварительно рендерится. Она дружественна к SEO, быстро реагирует, но также полностью поддерживается SWR на стороне клиента. Данные могут быть динамичными и автоматически обновляться со временем.

Компонент Article сначала отобразит предварительно сгенерированные данные, после гидратации страницы снова запросит последние данные, чтобы обновить их.

Комплексные ключи

useSWR можно использовать с ключами типов array и function. Для использования предварительно полученных данных с этими типами ключей необходимо сериализовать ключи fallback с помощью unstable_serialize.

import useSWR, { unstable_serialize } from 'swr'

export async function getStaticProps () {
  const article = await getArticleFromAPI(1)
  return {
    props: {
      fallback: {
        // ключ в виде массива с использованием unstable_serialize()
        [unstable_serialize(['api', 'article', 1])]: article,
      }
    }
  }
}

function Article() {
  // использование ключа в виде массива.
  const { data } = useSWR(['api', 'article', 1], fetcher)
  return <h1>{data.title}</h1>
}

export default function Page({ fallback }) {
  return (
    <SWRConfig value={{ fallback }}>
      <Article />
    </SWRConfig>
  )
}