Що таке React Server Components (RSC)?
1. Що таке React Server Components (RSC)
React Server Components (RSC) - це компоненти, які виконуються на сервері, а не в браузері, і при цьому інтегруються в одне дерево React із клієнтськими компонентами.
Простіше кажучи:
RSC - це спосіб рендерити частину React-застосунку на сервері, але при цьому залишати решту інтерактивною на клієнті, без дублювання логіки чи SSR-гідрації всього дерева.
2. Чим RSC відрізняються від SSR
| Критерій | SSR (Server-Side Rendering) | RSC (React Server Components) |
|---|---|---|
| Де виконується | Сервер генерує HTML | Сервер генерує React-структуру (дерево) |
| Що відправляється клієнту | Готовий HTML | Потік серіалізованих компонентів |
| Що робить клієнт | "Оживляє" HTML (hydration) | Об'єднує серверні і клієнтські компоненти |
| Коли виконується | При кожному запиті | Може бути при білді, при фетчі, або частково |
Де можна писати fetch | Зазвичай у getServerSideProps | Прямо всередині компонента! |
Тобто SSR = "рендер HTML на сервері", а RSC = "рендер React-компонентів на сервері без HTML".
3. Як працює механізм RSC
Крок 1. Поділ на типи компонентів
RSC вводить два типи компонентів:
| Тип | Де виконується | Чи можна використовувати Hooks / DOM |
|---|---|---|
| Server Component | Тільки на сервері | Не можна useState, useEffect, window, document |
| Client Component | У браузері | Можна все (хуки, DOM, події тощо) |
Позначення в коді:
// Це серверний компонент (за замовчуванням)
export default async function Page() {
const data = await fetch('https://api.example.com/posts').then(r => r.json());
return <PostList posts={data} />;
}
// Це клієнтський
"use client";
import { useState } from "react";
export function LikeButton() {
const [liked, setLiked] = useState(false);
return <button onClick={() => setLiked(!liked)}>{liked ? "heart" : "outline heart"}</button>;
}Крок 2. Серверний рендер повертає не HTML, а React Payload
React Server Components не відправляють HTML. Сервер генерує потік серіалізованих React-компонентів, який називається React Flight Data.
Приклад (спрощено):
[
["$","div",null,{"children":["Hello from server"]}],
["$","button","client:likeButton",{"children":["like"]}]
]Клієнт отримує цей "JSON-потік" і збирає дерево React за допомогою RSC runtime.
Тобто на клієнт приходить не HTML, а "інструкції" для React про те, які компоненти відрендерити і які з них клієнтські.
Крок 3. Об'єднання (гібридне дерево)
На клієнті React об'єднує два світи:
- Серверні компоненти - відрендерені заздалегідь (їхнього JS-коду навіть немає на клієнті),
- Клієнтські компоненти - завантажуються, гідруються і стають інтерактивними.
<App>
|-- <Header /> -> Server Component
|-- <PostList /> -> Server Component
| |-- <Post /> -> Server Component
| `-- <LikeButton /> -> Client Component
`-- <Footer /> -> Server ComponentТаким чином клієнт отримує мінімум JS - тільки для LikeButton.
Усе інше вже відрендерено на сервері і не потребує гідрації.
4. Переваги RSC
| Перевага | Чому це круто |
|---|---|
| Менше JS на клієнті | Клієнту взагалі не потрібен код серверних компонентів |
| Немає подвійного рендеру (як при SSR) | RSC не потребує гідрації HTML - немає дублювання |
| Гібридність | Можна змішувати серверні і клієнтські компоненти в одному дереві |
| Безпека | Серверні компоненти не потрапляють на клієнт - не можна випадково "злити" ключі чи API-токени |
| Швидший рендер великих списків / даних | Логіка і запити виконуються на сервері, а не в браузері |
| Сумісність зі Streaming SSR | Можна стрімити серверні і клієнтські частини асинхронно |
5. Приклад RSC у Next.js 13+ (App Router)
// app/page.tsx - Server Component (за замовчуванням)
import Posts from './Posts';
export default async function Page() {
const posts = await fetch('https://jsonplaceholder.typicode.com/posts').then(r => r.json());
return (
<main>
<h1>Server-rendered posts</h1>
<Posts posts={posts} />
</main>
);
}// app/Posts.tsx - Server Component
import LikeButton from './LikeButton';
export default function Posts({ posts }) {
return (
<ul>
{posts.map(p => (
<li key={p.id}>
{p.title} <LikeButton />
</li>
))}
</ul>
);
}// app/LikeButton.tsx - Client Component
"use client";
import { useState } from "react";
export default function LikeButton() {
const [liked, setLiked] = useState(false);
return (
<button onClick={() => setLiked(!liked)}>
{liked ? "liked" : "not liked"}
</button>
);
}Увесь список постів рендериться на сервері, а кнопка "лайк" інтерактивна, але завантажується окремим JS-чанком.
6. RSC != SSR
| Відмінність | SSR | RSC |
|---|---|---|
| Формат виводу | HTML | React Payload (інструкції) |
| Гідрація | Обов'язкова | Не потрібна |
| Де зберігається логіка даних | У "getServerSideProps" / API | Прямо в компонентах |
| Чи можна змішувати з клієнтськими компонентами | Обмежено | Так, гібридно |
| Продуктивність | Вища, ніж CSR, але потребує подвійного рендеру | Ще вища - менше JS і менше HTML |
Підсумок
React Server Components (RSC) - це новий фундамент React, який:
- переносить частину логіки і рендерингу на сервер,
- залишає інтерактивність клієнту,
- прибирає потребу в "hydration" для статичних частин,
- зменшує розмір JS і прискорює завантаження сторінок,
- і дає можливість змішувати серверний і клієнтський код в одному дереві.
Якщо SSR = "сервер генерує HTML", то RSC = "сервер генерує React-дерево". І це наближає React до universal rendering - розумної, гібридної моделі, де кожен компонент виконується там, де це вигідніше.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.