Серверные и клиентские компоненты
Разделяем подготовку данных и интерактивность интерфейса.
На этой странице
Для Next.js 16.3.8 (App Router) и React 19.3.0. Обновлено .
Сервер – программа, которая отвечает на запросы сайта. Клиент здесь – браузер пользователя. У них разные возможности: сервер может читать закрытые данные приложения, а браузер – реагировать на клики и работать с window.
Страницы и общие компоненты layout в App Router по умолчанию являются серверными компонентами. Они могут подготовить данные и описать интерфейс. Для состояния, обработчиков событий и браузерных API используем клиентские компоненты.
Небольшая клиентская часть
Сохраните модель lib/events.ts из статьи о маршрутах и карточку app/event-card.tsx из первого этапа. Создайте фильтр:
"use client";
import { useState } from "react";
import Link from "next/link";
import { EventCard } from "@/app/event-card";
import type { EventItem } from "@/lib/events";
export function EventFilter({ items }: { items: EventItem[] }) {
const [freeOnly, setFreeOnly] = useState(false);
const visible = freeOnly ? items.filter((item) => item.price === 0) : items;
return (
<section>
<button
type="button"
aria-pressed={freeOnly}
onClick={() => setFreeOnly((current) => !current)}
>
Только бесплатные
</button>
{visible.length === 0 ? (
<p>Ничего не найдено.</p>
) : (
<ul className="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
{visible.map((item) => (
<li key={item.id}>
<EventCard name={item.name} price={item.price} />
<Link href={`/events/${item.id}`}>Подробнее</Link>
</li>
))}
</ul>
)}
</section>
);
}Теперь серверная страница использует его:
import { events } from "@/lib/events";
import { EventFilter } from "./event-filter";
export default function EventsPage() {
return (
<main>
<h1>Афиша</h1>
<EventFilter items={events} />
</main>
);
}Директива "use client" стоит перед импортами. Она определяет, какой код нужен клиентской части: сам компонент и подключенные им зависимости. Страница, которая использует этот компонент, от этого не становится клиентской целиком. import type переносит только описание типа и не добавляет код данных в браузер.
Что происходит при открытии
- Браузер запрашивает страницу.
- Сервер готовит первоначальный HTML страницы.
- Браузер показывает HTML и загружает код клиентских компонентов.
- React подключает обработчики: фильтр становится интерактивным.
Последний шаг называется гидратацией. Клиентский компонент тоже может участвовать в подготовке первоначального HTML на сервере. Поэтому "use client" не означает «никогда не выполняется на сервере».
Не читайте window или localStorage прямо в теле компонента при его первом вызове. Например, обращаться к window.location можно из обработчика нажатия. Для работы с браузерными API после появления компонента есть useEffect. Для вычисления отфильтрованного списка этот хук не нужен.
Какие параметры получает клиентский компонент
В примере передается массив простых объектов с числами и строками. React умеет передавать такие данные. Обычный обработчик () => ... из серверного компонента передать клиентскому как prop нельзя. Обработчик должен принадлежать клиентской части. Серверные функции имеют отдельный механизм, который изучим в этапе форм.
Не подключайте в клиентском файле код, который обращается к базе данных или использует секретные ключи. Серверные модули можно дополнительно защитить пакетом server-only: после bun add server-only добавьте в их начало import "server-only". Если такой модуль попадет в клиентский код, сборка сообщит об ошибке.
use client и use server
| Запись | Назначение |
|---|---|
"use client" | Обозначает границу клиентского компонента и его зависимостей |
"use server" | Помечает серверные функции, которые можно вызывать специальным механизмом React |
Директива "use server" предназначена для серверных функций, которые вызываются через механизм React. Обычным серверным компонентам она не нужна. Страницы App Router и так по умолчанию выполняются на сервере, в том числе при сборке.
Попробуйте: уберите "use client" из фильтра и прочитайте сообщение Next.js. Верните директиву. Затем убедитесь, что серверная страница не получила её автоматически.
Далее – получение данных. Документация: компоненты и граница, use client, use server.