Загрузка данных в Server Components
Server Components выполняются на сервере и могут напрямую обращаться к данным.
Async-компоненты
// app/posts/page.tsx
export default async function Posts() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
return <ul>{posts.map((p) => <li key={p.id}>{p.title}</li>)}</ul>;
}
Компонент объявлен async, Next.js ждёт промис.
Доступ к БД напрямую
import { db } from '@/lib/db';
export default async function Users() {
const users = await db.user.findMany();
return <ul>{users.map((u) => <li key={u.id}>{u.name}</li>)}</ul>;
}
Не нужен API-роут для внутренней загрузки. Меньше кода, быстрее.
Переменные окружения
На сервере доступны все переменные:
const apiKey = process.env.API_KEY; // работает
const dbUrl = process.env.DATABASE_URL;
На клиенте — только NEXT_PUBLIC_*.
Параллельная загрузка
Плохо — последовательно:
const user = await getUser();
const posts = await getPosts();
const comments = await getComments();
Время = user + posts + comments.
Хорошо — параллельно:
const [user, posts, comments] = await Promise.all([
getUser(),
getPosts(),
getComments(),
]);
Время = max(user, posts, comments).
Динамические параметры
export default async function Post({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params;
const post = await getPost(id);
if (!post) notFound();
return <h1>{post.title}</h1>;
}
Search params
export default async function Search({
searchParams,
}: {
searchParams: Promise<{ q?: string }>;
}) {
const { q = '' } = await searchParams;
const results = await search(q);
return <ul>{results.map((r) => <li key={r.id}>{r.title}</li>)}</ul>;
}
Обработка ошибок
export default async function Post({ params }) {
const { id } = await params;
try {
const post = await getPost(id);
if (!post) notFound();
return <h1>{post.title}</h1>;
} catch (error) {
throw error; // поймает error.tsx
}
}
Suspense для медленных частей
import { Suspense } from 'react';
export default function Page() {
return (
<>
<Header />
<Suspense fallback={<PostsSkeleton />}>
<Posts />
</Suspense>
<Suspense fallback={<CommentsSkeleton />}>
<Comments />
</Suspense>
</>
);
}
Каждый блок грузится независимо. Страница не ждёт самого медленного.
Streaming
Next.js стримит HTML по мере готовности. Пользователь видит части страницы, пока грузятся остальные.
Когда использовать API-роуты
- Webhooks от внешних сервисов
- Публичные API для мобильных приложений
- Внешние интеграции
Для внутренней загрузки — прямое обращение к БД или fetch.
Итоги
- Server Components —
async/await - Прямой доступ к БД
Promise.allдля параллельностиparamsиsearchParams— промисыSuspenseдля стриминга- API-роуты для внешних клиентов