JavaRush /Курсы /Модуль 4: Node.js, Next.js и Angular /Ограничения Server Components: нет интерактивности, состо...

Ограничения Server Components: нет интерактивности, состояния

Модуль 4: Node.js, Next.js и Angular
7 уровень , 6 лекция
Открыта

1. Главные ограничения Server Components

Вот тут и начинается самое интересное. Server Components — это не "React как обычно", только быстрее. У них есть принципиальные ограничения, которые нужно понимать, чтобы не наступать на грабли.

Нет интерактивности

Server Component не может быть интерактивным.
Что это значит? Всё, что связано с обработкой событий на клиенте (клики, ввод текста, анимации, изменение состояния, работа с localStorage и т.п.), невозможно реализовать внутри Server Component.

Почему так?

  • Сервер не может реагировать на события, происходящие в браузере пользователя.
  • Код Server Component вообще не попадает в браузер — его там просто нет! Он "живёт" только на сервере, а клиент получает только результат рендера (HTML) и данные.

Примеры того, что не работает в Server Component

  • onClick, onChange и любые другие обработчики событий.
  • useState, useEffect, useReducer, useRef и любые React-хуки для состояния или эффектов.
  • Работа с браузерным API: window, document, localStorage, alert, prompt и т.д.
  • Динамическая навигация через useRouter().push() и т.п.

Если вы попробуете использовать что-то из этого в Server Component, Next.js вас строго отругает ошибкой на этапе сборки.

Нет состояния (state)

Server Component не может хранить или изменять состояние на клиенте.
— Нельзя использовать useState, useReducer, или любые другие хуки состояния.
— Нельзя делать что-то вроде:


// ❌ Не сработает!
const [count, setCount] = useState(0);

— Нельзя менять состояние по клику, потому что клика сервер "не увидит".

Нет эффектов (side effects)

Server Component не может использовать хуки жизненного цикла или эффекты (useEffect, useLayoutEffect и т.д.), потому что они нужны только на клиенте. Серверу не нужно "подписываться" на что-то, "чистить" после себя или реагировать на изменение DOM.

Нет доступа к браузерным API

Server Component не может обращаться к window, document, localStorage, sessionStorage, navigator и прочим прелестям браузерного мира. Всё это существует только в браузере, а не на сервере.

2. Что делать с ограничениями

Можно подумать: "Эй, зачем такие жёсткие рамки? Почему нельзя просто сделать всё как раньше?"
Причина проста: Server Component — это не код для браузера, а код для сервера! Его задача — сгенерировать HTML и данные, которые потом попадут в браузер. Он не может и не должен реагировать на действия пользователя после того, как страница уже загружена.

Это похоже на ресторан: повар на кухне (сервер) готовит блюдо, а вы (клиент) уже едите его за столом. Повар не может добавить вам соли по щелчку пальцев — он уже ушёл готовить для других клиентов.

Плюсы такого подхода:

  • Меньше JS на клиенте — быстрее загрузка, меньше ресурсов.
  • Можно делать тяжёлые операции (запросы, обработку данных) на сервере, не нагружая браузер.
  • Безопасность: секретные ключи и доступ к базе данных не утекают на клиент.
  • Легче поддерживать SEO и рендерить страницы для поисковиков.

Как понять, что компоненту нужна интерактивность?

Очень просто: если компонент должен реагировать на действия пользователя после загрузки страницы — это Client Component.

Примеры:

  • Кнопка "лайк", которая увеличивает счётчик при клике.
  • Форма с полями ввода, где пользователь что-то пишет.
  • Выпадающее меню, которое открывается по наведению.
  • Любая анимация, зависящая от действий пользователя.

Противоположные примеры (Server Component):

  • Список статей, полученных из базы данных.
  • Статичная информация о товаре.
  • SEO-метаданные, Open Graph, хлебные крошки.
  • Любой контент, который не меняется без действий пользователя.

Как сделать компонент интерактивным? ("use client")

Когда вам нужна интерактивность, оборачивайте нужный компонент в Client Component. Для этого достаточно добавить в начало файла строку:

"use client";

Теперь внутри этого компонента можно использовать useState, useEffect, обработчики событий, работать с window и прочее. Такой компонент будет загружен на клиент и сможет реагировать на действия пользователя.

Важно:
— Весь код в Client Component попадёт в JS-бандл и будет исполняться в браузере.
— Можно смешивать Server и Client Components: Server "собирает" структуру страницы, Client "оживляет" отдельные части.

3. Примеры: что можно и что нельзя

Пример 1: Server Component (только отображение данных)


// app/products/page.jsx (Server Component по умолчанию)
import { getProducts } from "@/lib/db";

export default async function ProductsPage() {
  const products = await getProducts();
  return (
    <ul>
      {products.map(p => (
        <li key={p.id}>{p.name}</li>
      ))}
    </ul>
  );
}

Здесь всё хорошо:
— Нет интерактивности, только вывод данных.
— Можно делать async/await, обращаться к базе.

Пример 2: Ошибка — попытка обработать событие в Server Component


// ❌ Это не сработает!
export default function Counter() {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount(count + 1)>
      Clicked {count} times
    </button>
  );
}

Результат:
Next.js ругнётся: "useState нельзя использовать в Server Component".

Пример 3: Как правильно — разделяем Server и Client Components

Server Component:


import Counter from "./Counter";

export default function Page() {
  return (
    <main>
      <h1>Добро пожаловать!</h1>
      <Counter />
    </main>
  );
}

Client Component (Counter.jsx):


"use client";
import { useState } from "react";

export default function Counter() {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount(count + 1)>
      Кликнули {count} раз
    </button>
  );
}

Теперь всё работает:
— Server Component рендерит всю страницу.
— Client Component "оживляет" только нужную часть.

4. Полезные нюансы

Что можно и нельзя в Server Components

Возможность Server Component Client Component
useState, useEffect
Обработчики событий (onClick, onChange и т.д.)
Доступ к window, document
async/await (fetch, db)
Работа с localStorage
Рендер на сервере
Входит в JS-бандл клиента

Как это влияет на архитектуру приложения

Server Components отлично подходят для:

  • Получения и отображения данных с сервера.
  • Генерации страниц для SEO.
  • Быстрого рендера больших объёмов информации.
  • Секретных операций (доступ к базе, API-ключи).

Client Components нужны для:

  • Любой интерактивности (формы, кнопки, анимации).
  • Хранения состояния на клиенте.
  • Работы с браузерными API.

Совет:
Делайте как можно больше компонентов серверными, а клиентскими — только то, что действительно нужно "оживить". Это уменьшит размер JS, ускорит загрузку, и сделает приложение более отзывчивым.

5. Типичные ошибки при работе с Server Components

Ошибка №1: попытка использовать useState или обработчики событий в Server Component.
Это не сработает: Next.js выдаст ошибку. Не забывайте: никакой интерактивности на сервере!

Ошибка №2: попытка обратиться к window, document, localStorage в Server Component.
Эти объекты существуют только в браузере. На сервере их нет, и попытка обращения вызовет ошибку.

Ошибка №3: забыли добавить "use client" в компонент с интерактивностью.
Если компонент должен реагировать на клики, а вы не сделали его клиентским — ничего работать не будет, а Next.js предупредит об ошибке.

Ошибка №4: чрезмерное использование Client Components.
Если вы делаете всё клиентским "на всякий случай", теряются преимущества Server Components: увеличивается размер бандла, страница грузится дольше.

Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ