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