Загрузка...
Загрузка...
Продолжая работу с платформой, вы принимаете условия Политики конфиденциальности и использование файлов cookie.
React Server Components (RSC) это компоненты, которые выполняются исключительно на сервере. Их код никогда не попадает в JavaScript-бандл, который скачивает браузер. В App Router Next.js (начиная с версии 13) все компоненты являются серверными по умолчанию.
До появления RSC весь React-код отправлялся в браузер. Даже если компонент просто отображал данные из базы, его код, зависимости и логика включались в клиентский бандл.
Server Components решают три проблемы:
Размер бандла. Код серверных компонентов и их зависимости не отправляются клиенту. Если ты используешь тяжелую библиотеку для обработки данных, она остается на сервере.
Прямой доступ к данным. Серверные компоненты могут напрямую обращаться к базе данных, файловой системе, env-переменным. Не нужен промежуточный API-слой.
Безопасность. Секреты (API-ключи, строки подключения к БД) никогда не попадают к клиенту.
// Серверный компонент (по умолчанию)
// Выполняется на сервере, код не попадает в бандл
import { db } from '@/lib/db'
export default async function ProblemsCount() {
const count = await db.problem.count()
return <p>Задач на Hack Frontend: {count}</p>
}
// Клиентский компонент
// Помечаем директивой 'use client'
'use client'
import { useState } from 'react'
export default function LikeButton() {
const [liked, setLiked] = useState(false)
return (
<button onClick={() => setLiked(!liked)}>
{liked ? 'Убрать лайк' : 'Лайкнуть'}
</button>
)
}
| Задача | Серверный | Клиентский |
|---|---|---|
| Загрузка данных из БД/API | ✓ | |
| Доступ к env-переменным, файлам | ✓ | |
| Тяжелые зависимости (markdown-парсер и т.д.) | ✓ | |
| useState, useEffect, useRef | ✓ | |
| onClick, onChange, onSubmit | ✓ | |
| Browser API (localStorage, geolocation) | ✓ | |
| React Context (useContext) | ✓ |
Next.js выполняет серверные компоненты и создает специальный формат (RSC Payload), который описывает результат рендеринга.
RSC Payload передается в браузер вместе с HTML. Клиентские компоненты гидратируются, серверные уже отрендерены.
При навигации Next.js запрашивает RSC Payload для нового роута. Серверные компоненты перерендериваются на сервере, клиентские сохраняют свое состояние.
Самый распространенный паттерн: серверный компонент загружает данные и передает их клиентскому через props:
// app/problems/page.tsx (серверный)
import { db } from '@/lib/db'
import { ProblemList } from './problem-list'
export default async function ProblemsPage() {
const problems = await db.problem.findMany({
orderBy: { difficulty: 'asc' }
})
return <ProblemList problems={problems} />
}
// app/problems/problem-list.tsx (клиентский)
'use client'
import { useState } from 'react'
export function ProblemList({ problems }) {
const [filter, setFilter] = useState('all')
const filtered = filter === 'all'
? problems
: problems.filter(p => p.difficulty === Number(filter))
return (
<div>
<select onChange={e => setFilter(e.target.value)}>
<option value="all">Все</option>
<option value="1">Легкие</option>
<option value="2">Средние</option>
<option value="3">Сложные</option>
</select>
<ul>
{filtered.map(p => (
<li key={p.id}>{p.name}</li>
))}
</ul>
</div>
)
}
Клиентский компонент может принимать серверный через children. Это позволяет делать интерактивные обертки, не теряя преимущества серверного рендеринга:
// Клиентский компонент-обертка
'use client'
import { useState } from 'react'
export function Accordion({ title, children }) {
const [open, setOpen] = useState(false)
return (
<div>
<button onClick={() => setOpen(!open)}>{title}</button>
{open && children}
</div>
)
}
// Серверный компонент использует клиентскую обертку
import { Accordion } from './accordion'
import { db } from '@/lib/db'
export default async function FAQ() {
const items = await db.faq.findMany()
return (
<div>
{items.map(item => (
<Accordion key={item.id} title={item.question}>
<p>{item.answer}</p>
</Accordion>
))}
</div>
)
}
Важно:
Серверный компонент нельзя импортировать внутри клиентского. Если ты добавишь 'use client' в файл, все его импорты тоже станут клиентскими. Передавай серверные компоненты только через props или children.
На собеседовании:
Частая ошибка на собеседовании: путать Server Components и SSR. SSR рендерит весь React-дерево на сервере один раз и отправляет HTML. Server Components это другая модель: часть дерева живет на сервере постоянно и никогда не отправляет свой код клиенту. При навигации серверные компоненты перерендериваются на сервере.