webroad.online
  1. 1Веб
  2. 2HTML
  3. 3CSS
  4. 4JavaScript
  5. 5TypeScript
  6. 6Git
  7. 7Инструменты
  8. 8React
  9. 9Стейт-менеджмент
  10. 10Next.js
  11. 11Формы
  12. 12Данные и бэкенд
  13. 13SEO
  14. 14Tailwind CSS
  15. 15Анимации
  16. 16Тестирование
  17. 17Архитектура
Next.js · Урок 6 из 12

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

Данные прямо в Server Components, параллельно, Suspense и params как Promise.

Обновлено

Что значит получение данных в Next

Получение данных (data fetching) = загрузка данных (из БД, из API), которые нужны странице. В Next App Router место по умолчанию — Server Component: async-функция, которая читает данные напрямую и рендерит результат.

export default async function Page() {
  const posts = await db.post.findMany()       // ORM, SQL, fetch — что угодно
  return <PostList posts={posts} />
}

По сравнению с классическим React (useEffect + fetch + useState): нет состояния загрузки на клиенте, нет промежуточного API-маршрута, нет раскрытых секретов, нет водопада клиент → сервер → БД.

Способы получать данные — и когда

Способ Где Когда
прямой await в Server Component сервер по умолчанию — любой вывод данных
Promise, переданный в Client Component + use() сервер запускает, клиент читает клиентскому компоненту нужны данные, но хочется стриминга
TanStack Query клиент очень интерактивные данные (polling, бесконечная прокрутка) — Серверное состояние
Route Handler сервер API для других / вебхуки — не для своих страниц
useEffect + fetch клиент почти никогда

Параллельно, а не каскадом

Водопад (waterfall) = запросы, которые без причины ждут друг друга.

// ✗ водопад — 2 × время
const user = await getUser(id)
const posts = await getPosts(id)

// ✓ параллельно
const [user, posts] = await Promise.all([getUser(id), getPosts(id)])

Что такое стриминг

Без стриминга пользователь видит страницу, только когда готовы все данные. Со стримингом сервер отправляет HTML частями: готовое показывается сразу, медленные части приходят, когда закончат.

Инструмент — <Suspense>.

export default function Page() {
  return (
    <>
      <Header />                                   {/* появляется сразу */}
      <Suspense fallback={<Skeleton />}>
        <Recommendations />                        {/* async, появляется, когда готов */}
      </Suspense>
    </>
  )
}

loading.tsx = автоматический <Suspense> вокруг всей страницы.

Promise, переданный клиенту

Запрос запускается на сервере, а читается в Client Component:

// сервер
const statsPromise = getStats()                  // без await — не блокирует
<Suspense fallback={<Spinner />}>
  <Stats data={statsPromise} />
</Suspense>

// клиент
'use client'
import { use } from 'react'
export function Stats({ data }: { data: Promise<Stats> }) {
  const stats = use(data)                        // приостанавливается до получения
}

Данные времени выполнения

cookies(), headers(), searchParams, params (для значений, не сгенерированных заранее) зависят от запроса — их нельзя узнать при сборке. Компоненты, которые их читают, становятся динамическими и должны быть внутри <Suspense>, чтобы остальная страница осталась статичной. Именно так в этом приложении показывается ваш прогресс.

Дедупликация

Одна и та же функция вызывается из layout + page + generateMetadata?

Инструмент Время жизни
cache() из React в пределах одного запроса
'use cache' постоянно, между запросами — урок Кэш

Коротко

  • Данные → прямо в Server Components через await.
  • Promise.all для независимых запросов.
  • <Suspense> для стриминга; данные времени выполнения — внутри Suspense.

Официальные источники

Упражнения

Была ли страница полезной?

Один клик — без регистрации.