110 lines
4.7 KiB
Markdown
110 lines
4.7 KiB
Markdown
|
|
---
|
|||
|
|
title: Начальные данные для клиентских хуков
|
|||
|
|
description: Как дать клиентским GET-хукам начальные REST-данные.
|
|||
|
|
keywords: [rest, swr, fallback, initial data, client hooks, unstable_serialize, isr, ssr]
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# Начальные данные для клиентских хуков
|
|||
|
|
|
|||
|
|
Как дать клиентским 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](./server-await.md). Если данные зависят от состояния браузера, используйте [Клиентский GET-хук](./client-get-hook.md).
|