Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Загрузка и потоковая отрисовка

Пока серверный компонент ждёт данные, посетитель видит пустой экран. Чтобы этого не было, Next.js умеет отправлять страницу частями: сначала то, что готово, и заглушку на месте медленной части, затем — недостающий кусок. Такой способ называют потоковой отрисовкой (streaming).

Медленные данные

Для опыта сделаем компонент комментариев, который загружается две секунды. Создайте components/Comments.tsx:

// components/Comments.tsx
export default async function Comments() {
  await new Promise((resolve) => setTimeout(resolve, 2000));
  const comments = ['Олег: Отличная статья!', 'Анна: Спасибо!'];
 
  return (
    <ul>
      {comments.map((text) => (
        <li key={text}>{text}</li>
      ))}
    </ul>
  );
}

Задержка имитирует медленный запрос к базе. Если вставить <Comments /> в страницу статьи как обычно, вся страница будет открываться две секунды.

Файл loading.tsx

Самый простой способ — положить рядом со страницей файл loading.tsx:

// app/posts/[slug]/loading.tsx
export default function Loading() {
  return <p>Загружаем статью...</p>;
}

Пока страница статьи готовится, на её месте виден текст «Загружаем статью...». Макеты — шапка и меню — показываются сразу, заглушка заменяет только содержимое страницы.

Suspense для части страницы

Файл loading.tsx заменяет всю страницу. Чтобы статья появилась сразу, а ждали только комментарии, оберните медленный компонент в Suspense из React:

// app/posts/[slug]/page.tsx
import { Suspense } from 'react';
import { notFound } from 'next/navigation';
import Comments from '@/components/Comments';
import { getPost } from '@/lib/posts';
 
export default async function PostPage({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params;
  const post = await getPost(slug);
  if (!post) notFound();
 
  return (
    <article>
      <h1>{post.title}</h1>
      <p>{post.body}</p>
      <Suspense fallback={<p>Загружаем комментарии...</p>}>
        <Comments />
      </Suspense>
    </article>
  );
}

Откройте /posts/hello-nextjs: статья видна сразу, под ней — «Загружаем комментарии...», а через две секунды на этом месте появится список.

Как это устроено

СпособЧто заменяет заглушкаГде пишется
loading.tsxВсю страницу папкиФайл рядом с page.tsx
SuspenseТолько обёрнутую частьВнутри разметки

Свойство fallback — то, что показать вместо содержимого, пока оно не готово. На одной странице может быть несколько Suspense, каждый появляется независимо.

Частая ошибка

Загрузить медленные данные в самой странице через await, а потом передать их в компонент внутри Suspense. Страница всё равно будет ждать, ведь await стоит выше. Медленный запрос должен выполняться внутри компонента, который обёрнут в Suspense, как Comments в примере.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.