Server Components ломают привычное разделение на «UI» и «данные». За полгода мы выработали набор паттернов, которые помогают команде не путаться. Текст полезен, если у вас уже есть один-два проекта на App Router.
Паттерн 1: server-обёртка с client-листом
Серверный компонент фетчит данные и передаёт их в клиентский для интерактивности. Клиентский компонент ничего не знает про источник данных. Это ломает много привычек - но ровно это и нужно для маленьких бандлов.
Паттерн 2: client-shell с children
Когда нужна обёртка с клиентским состоянием (например, accordion), но содержимое - серверное. Передаём содержимое через children - Next.js рендерит его на сервере, а клиентский shell просто принимает результат.
Паттерн 3: parallel data fetching
Несколько серверных компонентов на одной странице фетчат параллельно. Никакой Promise.all не нужен - рантайм сам параллелит. Главное - не цеплять fetch внутри одного компонента в цепочку, иначе получите водопад.
Паттерн 4: Suspense на каждом fetch
Каждый серверный компонент с долгим fetch заворачиваем в Suspense с loading.tsx. Это даёт streaming: пользователь видит часть страницы, пока другая ещё фетчится. Резко улучшает perceived performance.
Антипаттерны, которые мы запретили
- Передача функций из server в client - невозможно, не пытайтесь.
- Большие объекты в props - сериализация через wire становится узким местом.
- useEffect для первичной загрузки данных - это всегда симптом, что компонент должен быть серверным.
- Client-компонент, импортирующий server-компонент напрямую (только через children).
Граница client/server и где её проводить
Главное правило, которое мы выработали: граница идёт по интерактивности, а не по «типу данных». Если компонент реагирует на ввод пользователя или меняет state - клиент. Всё остальное - сервер.