tgoop.com/startpoint_dev/65
Last Update:
Server Components и Server Actions. Часть 1.
Саму концепцию серверных компонентов нам представили еще несколько лет назад. В том числе, она активно используется в 14 версии Next.js в App Router, который создатели фреймворка теперь предлагают по умолчанию для разработки новых приложений. Однако в React серверные компоненты и экшены были анонсированы только в 19 версии. Я решила посмотреть поподробнее, что это за покемоны.
Server Component - это неинтерактивный компонент, который работает исключительно на стороне сервера.
Server Action - это функция, которая работает на сервере, но может использоваться клиентским компонентом, например как пропс-промис, который передается в этот компонент.
Давайте посмотрим на ещё несколько интересных примеров работы с ними поподробнее. Для них будем использовать все тот же Next.js 15, который поддерживает React 19.
👀 По умолчанию в App Router все страницы и компоненты внутри них являются серверными, до тех пор, пока мы не указали обратное.
В чем особенности серверного компонента в сравнении с клиентским
🔹 Серверный компонент может быть асинхронным.
Пример простого серверного компонента, который получает данные из API другого сервиса и сразу же отображает их:
export async function List() {
const data = (await fetch('https://dummyjson.com/products/search?limit=10').then((res) => res.json()));
console.log('[List] Server Component Render');
return (
<ul>
{data.products.map((product) => (
<li key={product.id}>
{product.id}: <b>{product.title}</b>
</li>
))}
</ul>
);
}Здесь нам не нужно дополнительное состояние loading внутри компонента, т.к. мы работаем в едином потоке. Вместо запроса к другому API, мы можем использовать запрос на чтение из файла или базы данных.
🔹 Серверный компонент рендерится только один раз на сервере.
Для компонента выше у нас будет всего лишь один вывод в консоль '[List] Server Component Render' - на сервере. При классическом Server Side Rendering таких выводов будет два - один на сервере, во время формирования HTML, и один на клиенте - во время гидратации. Для серверных же компонентов гидратация не нужна.
🔹 Серверный компонент не может рендерится напрямую в клиентском компоненте, но его можно передавать туда как props.
Рассмотрим пример, у нас есть компонент Switcher, который в зависимости от состояния отрисовывает один или другой компонент:
type ComponentType = 'list' | 'searchedList';
export function Switcher({ ListComponent, SearchedListComponent }: Props) {
const [type, setType] = useState<ComponentType>('list');
const handleClick = (newType: ComponentType) => () => setType(newType);
return (
<section>
<div>
<button onClick={handleClick('list')}>List</button>
<button onClick={handleClick('searchedList')}>Searched List</button>
</div>
{type === 'list' ? ListComponent : SearchedListComponent}
</section>
);
}
Дальше как пропсы в этот компонент мы можем передать как клиентский компонент, так и серверный:
<Switcher
// серверный компонент
ListComponent={<List />}
// клиентский компонент
SearchedListComponent={<SearchedList />}
/>
🔹 При динамической подгрузке серверные компоненты передаются на клиент не в виде HTML, а в специальном формате
Вот как примерно выглядят пришедшие в браузер данные для новой страницы /about в нашем приложении на Next.js:
5:I["(app-pages-browser)/./node_modules/next/dist/client/link.js",...
6:I["(app-pages-browser)/...
7:I["(app-pages-browser)/...
2:{"name":"","env":"Server","owner":null}
1:D"$2"
4:{"name":"About","env":"Server","owner":null}
3:D"$4"
3:["$","div",null,{"className":"page_page__bHvK0","children":...
...
Из этой структуры React на клиенте сможет построить DOM-дерево, но при этом не будет производить процесса гидратации, так как серверные компоненты не обладают динамикой.
📂 Подробнее примеры можно посмотреть в нашем репозитории на GitHub.
А в следующей части поговорим про Server Actions.
BY Настя Котова // Frontend & Node.js
Share with your friend now:
tgoop.com/startpoint_dev/65
