Skip to content

Начальные данные для клиентских хуков

Как дать клиентским GET-хукам начальные REST-данные.

Эта стратегия используется, когда данные должны быть запущены на сервере, но потребляться на клиенте через GET-хуки REST-клиента.

Технически это делается через SWRConfig fallback: сервер передаёт промис в fallback, а клиентский хук использует тот же SWR-ключ.

Когда использовать

  • Внутри страницы есть Client Components с GET-хуками.
  • Нужно начать загрузку данных на сервере раньше.
  • Клиентский компонент должен остаться обычным потребителем useGetPetList(...).
  • Не нужно писать отдельный prop-drilling для начальных данных.

Рендер страницы

Перед этой стратегией сначала определите рендер маршрута. Серверный preload для fallback подчиняется тем же правилам, что и любой серверный запрос в page.tsx или layout.tsx.

Если данные общие и могут обновляться по интервалу, сохраняйте static/ISR. Если preload зависит от cookie, headers, searchParams, no-store или персональных данных пользователя, маршрут становится dynamic/SSR.

SWRConfig fallback не должен быть причиной отключать ISR на всякий случай. Он только передаёт клиентскому GET-хуку данные, которые уже были запущены на сервере.

Ключ хука

ts
// src/infrastructure/pet-store-api/hooks/use-get-pet-list.hook.ts
export const getPetListKey = (status: PetStatus) =>
  ['pet-store-api', 'pet', 'list', status] as const

Ключ экспортируется из REST-модуля, потому что он нужен и GET-хуку, и серверному SWRConfig fallback.

Пример layout

tsx
// src/app/(routes)/pets/layout.tsx
import type { ReactNode } from 'react'
import { SWRConfig, unstable_serialize } from 'swr'
import {
  getPetListKey,
  petStoreApi,
} from 'infrastructure/pet-store-api'

type PetsLayoutProps = {
  children: ReactNode
}

export default async function PetsLayout({ children }: PetsLayoutProps) {
  const availablePetsPromise = petStoreApi.pet.findPetsByStatus({
    status: 'available',
  })

  return (
    <SWRConfig
      value={{
        fallback: {
          [unstable_serialize(getPetListKey('available'))]: availablePetsPromise,
        },
      }}
    >
      {children}
    </SWRConfig>
  )
}

Если GET-хук использует array-key, ключ для fallback сериализуется через unstable_serialize.

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

tsx
'use client'

import { useGetPetList } from 'infrastructure/pet-store-api'

export function PetList() {
  const { data: pets, isLoading } = useGetPetList('available')

  if (isLoading) return <div>Загрузка...</div>

  return (
    <ul>
      {pets?.map((pet) => (
        <li key={pet.id}>{pet.name}</li>
      ))}
    </ul>
  )
}

Компонент не знает, что данные были запущены на сервере. Он использует обычный GET-хук REST-клиента.

Что важно

  • Ключ fallback должен совпадать с ключом GET-хука.
  • Серверный код вызывает метод клиента, а не GET-хук.
  • Клиентский компонент вызывает GET-хук, а не useSWR напрямую.
  • Эта стратегия не означает ручную работу с кешем в компонентах.

Когда не использовать

Если данные нужны только серверному компоненту, используйте Серверный await. Если данные зависят от состояния браузера, используйте Клиентский GET-хук.