JavaRush /Курсы /Модуль 4: Node.js, Next.js и Angular /Server Components в Next.js 15: концепция и преимущества

Server Components в Next.js 15: концепция и преимущества

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

1. Введение: зачем нужны Server Components?

Если вы когда-либо писали React-приложения, то знаете: весь ваш код работает в браузере пользователя, даже если он занимается, скажем, только загрузкой данных или подготовкой HTML. Это иногда напоминает ситуацию, когда вы зовёте официанта, чтобы он приготовил вам кофе… прямо у вас за столиком. Не очень удобно, правда?

Server Components (далее — SC или серверные компоненты) — это новая концепция, которая позволяет часть React-компонентов выполнять не в браузере, а на сервере. Это как если бы официант готовил кофе на кухне, а вам приносил уже готовый напиток.

Краткое определение
Server Component — это React-компонент, который выполняется на сервере, а не в браузере. Его результат (HTML, данные) отправляется пользователю, а JS-код компонента не попадает в клиентский бандл.

Как это работает? (Общая схема)

Давайте разберёмся на пальцах. Представьте, что у вас есть такая структура компонентов:


<App>
  <Header />
  <UserProfile />
  <ProductList />
  <Footer />
</App>

В классическом React все эти компоненты грузятся и работают в браузере. Но если Header, ProductList и Footer — просто отображают данные, которые можно подготовить на сервере, зачем тянуть их JS-код пользователю? Пусть сервер сам подготовит HTML, а браузер просто покажет его.

Вот как это выглядит с Server Components:

  • Server Component: выполняется только на сервере, может обращаться к базе данных, секретам, API, и возвращает только результат (HTML, данные).
  • Client Component: обычный React-компонент, работает в браузере, умеет реагировать на клики, хранить состояние, использовать хуки (useState, useEffect).
graph TD
    A[Server Component] -->|HTML, данные| B(Браузер)
    C[Client Component] -->|JS-код, интерактивность| B
  
Схема взаимодействия серверных и клиентских компонентов

2. Преимущества Server Components

Меньше JavaScript на клиенте

Главное преимущество: код Server Component не попадает в браузер. Это значит, что ваши пользователи не качают лишний JS, не ждут пока он загрузится и не тратят ресурсы браузера на его выполнение.

Пример:
Если компонент ProductList грузит товары из базы, фильтрует их, форматирует, а потом просто показывает таблицу — всё это может быть сделано на сервере. В браузер попадёт только готовый HTML.

Доступ к серверным ресурсам

Server Component может напрямую обращаться к базе данных, приватным API, файловой системе. Не нужно городить API-эндпоинты или прокидывать секреты на клиент.


// app/products/page.tsx
import { getProducts } from '@/lib/db';

export default async function ProductList() {
  const products = await getProducts(); // Прямой доступ к базе!
  return (
    <ul>
      {products.map(p => <li key={p.id}>{p.title}</li>)}
    </ul>
  );
}

Улучшение производительности (и Core Web Vitals)

  • Меньше JS — быстрее загрузка, выше рейтинг Google.
  • Быстрее первый рендер: HTML генерируется на сервере.
  • Меньше "hydration" — браузеру не нужно оживлять статичный контент.

Простота кода

  • Не нужно писать лишние API-эндпоинты.
  • Не нужно думать о синхронизации состояния между сервером и клиентом.
  • Можно использовать обычные async/await, любые серверные библиотеки.

Безопасность

  • Секреты (API-ключи, пароли) не уходят на клиент.
  • Нет риска случайно "засветить" приватные данные.

3. Как узнать, что компонент — Server Component?

В Next.js 15 всё, что находится в папке app/ — по умолчанию Server Component.


// app/page.tsx
export default function Home() {
  // Это серверный компонент!
  return <h1>Привет с сервера!</h1>;
}

Как сделать компонент клиентским?

Если вам нужна интерактивность (клик, useState, useEffect), добавьте в начало файла директиву "use client":


// app/components/Counter.tsx
"use client";

import { useState } from "react";

export default function Counter() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(count + 1)}>
      Кликнули {count} раз
    </button>
  );
}

4. Пример: смешанная иерархия компонентов

Давайте соберём простую страницу интернет-магазина:


<App>
  <Header />           // Server Component
  <ProductList />      // Server Component
  <ProductCard />      // Server Component
  <AddToCartButton /> // Client Component
  <Footer />           // Server Component
</App>
  • ProductList и ProductCard могут быть серверными: они получают данные, отображают товары.
  • AddToCartButton — клиентский компонент: только он реагирует на клики, хранит локальное состояние.

// app/products/ProductList.tsx
import ProductCard from './ProductCard';
import { getProducts } from '@/lib/db';

export default async function ProductList() {
  const products = await getProducts();
  return (
    <div>
      {products.map(p => <ProductCard key={p.id} product={p} />)}
    </div>
  );
}

// app/products/ProductCard.tsx
import AddToCartButton from './AddToCartButton';

export default function ProductCard({ product }) {
  return (
    <div>
      <h2>{product.title}</h2>
      <AddToCartButton productId={product.id} />
    </div>
  );
}

// app/products/AddToCartButton.tsx
"use client";

export default function AddToCartButton({ productId }) {
  return (
    <button onClick={() => alert(`Добавили товар ${productId} в корзину!`)}>
      В корзину
    </button>
  );
}

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

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

Можно Нельзя
  • Использовать async/await (сервер сам подождёт данные)
  • Импортировать серверные библиотеки (например, для работы с базой, файловой системой)
  • Передавать пропсы клиентским компонентам
  • Использовать хуки состояния и эффекта (useState, useEffect, useReducer и др.)
  • Обрабатывать события пользователя (onClick, onChange и т.д.)
  • Использовать window, document, localStorage

Запомните:
Server Component — это про подготовку данных и HTML на сервере. Всё, что связано с интерактивностью — только в Client Component.

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

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

Это позволяет строить гибкие, быстрые и масштабируемые приложения, где большая часть кода работает на сервере, а клиенту достаётся только то, что действительно нужно.

Чем Server Components отличаются от SSR и SSG?

  • SSR (Server-Side Rendering):
    Сервер генерирует HTML, но весь JS-код всё равно отправляется на клиент, чтобы "оживить" страницу (hydration).
  • SSG (Static Site Generation):
    HTML готовится заранее (на build), но опять же, JS-код компонентов попадает в браузер.
  • Server Components:
    Генерируют HTML на сервере, но сам JS-код компонента не отправляется на клиент вообще. Только те компоненты, которые нужны для интерактивности, попадают в клиентский бандл.

6. Типичные ошибки и подводные камни

Ошибка №1: попытка использовать useState или useEffect в Server Component.
Компилятор Next.js вас тут же отругает: Hooks can only be used in Client Components. Не забывайте про "use client"!

Ошибка №2: импорт клиентского компонента в серверный без директивы.
Если вы импортируете компонент с "use client" в обычный файл, Next.js автоматически делает весь файл клиентским. Иногда это не то, что вы хотели — следите за этим.

Ошибка №3: попытка использовать window, document, localStorage и прочие браузерные API.
В Server Component их просто нет, потому что код выполняется на сервере. Если очень хочется — делайте отдельный Client Component.

Ошибка №4: ожидание, что Server Component "оживёт" на клиенте.
Server Component не может реагировать на клики, хранить состояние, подписываться на события. Для этого нужны Client Components.

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