Skip to content

Серверные и клиентские компоненты

Разделяем подготовку данных и интерактивность интерфейса.

On this page

Для Next.js 16.3.8 (App Router) и React 19.3.0. Обновлено .

Сервер – программа, которая отвечает на запросы сайта. Клиент здесь – браузер пользователя. У них разные возможности: сервер может читать закрытые данные приложения, а браузер – реагировать на клики и работать с window.

Страницы и общие компоненты layout в App Router по умолчанию являются серверными компонентами. Они могут подготовить данные и описать интерфейс. Для состояния, обработчиков событий и браузерных API используем клиентские компоненты.

Небольшая клиентская часть

Сохраните модель lib/events.ts из статьи о маршрутах и карточку app/event-card.tsx из первого этапа. Создайте фильтр:

app/events/event-filter.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>
  );
}

Теперь серверная страница использует его:

app/events/page.tsx
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 переносит только описание типа и не добавляет код данных в браузер.

Что происходит при открытии

  1. Браузер запрашивает страницу.
  2. Сервер готовит первоначальный HTML страницы.
  3. Браузер показывает HTML и загружает код клиентских компонентов.
  4. 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.