Галоўная / Артыкулы / React Server Components: Архітектура, яка стоўіць за безпакетным відрисовванням.

React Server Components: Архітектура, яка стоўіць за безпакетным відрисовванням.

З'ясаваце прычыны створэння React Server Components – від розміру пакета та проблем з обробкай дадзеных да межы сервера та кліента і навантажэння RSC.

3487 слоў

Якщо вы паслаеце час на спробы зразумець React Server Components і ў выйнае стаўліваліся яшчэ болей запытаныя, чым на пачатку, гэта не азнака таго, што вам не хапае чагось бяспадзейнага. Цэта азнака таго, што пояснення, якія вы знаходзілі, былі часткаю проблемы. Некалькі гадоў офіцыйныя апісанні называлі Server Components «компонентамі, якія рэндаруюцца на серверы», фразаю, якая падобна да таго, што вже робілі getServerSideProps або класычны серверны рэндарынг у Next.js. Потым з’явілася тэза, што гэтыя компоненты «не выкладжуць ніякога JavaScript на кліента», што звучыць больш як трюк для пасібнасці, чым як новы спосаб структуравання прыемплі. Потым з’явіўся App Router, і раптам кожны файл у проекте Next.js стаў серверным компонентам, якщо толькі вы не дадзеце спецыяльныя строку ў верхней часты файлу.

Гэтыя плутанніцы не былі вашай адказнасцю. Яны выйшлі таму, што сапраўдзіка новы парадыгм быў апісаны за дапамогою слоўніку, запозначанага з старэйшага парадыгмы. Цяны кансалтатывацый метыце запэўніць прыкрыцча гэтага разліку. Калі вы заканчыце чытаць, вы должны зразумець не толькі механізмы Server Components, але і прычыны, якія робяць іх абсалютна іншым спосабам разумення React-зяўванняў.

Проблема, якую на самай працоўдзе рашаюць RSC

Перш чым падыходзіць да таго, як функцыонуюць Server Components, корыстна зразумець, што спакусіла React да ўжоўвання іх. Проблема ніколі не была ў тым, што серверная рэндарынацыя працавала занадта медленна. Асалодныя проблемы — у тым, што модэль компанентаў React быў створаны на падставе прыпуску, што ўсё відбываецца ў браузеры, нават у тых случаях, калі гэты прыпуск даваў непатрэбныя затраты.

Пастка розмеру пакета

У класычным модэлі React кожны компанент, які вы ствараеце, ператвараецца на JavaScript, які падае ў браузер, без выключэння. Не мае значэння, чы рэндаруець гэты компанент проста якісь статычны markdown, выкарыстоўвае просты расчыт даты чы падключаецца да базы даных. Калі ён знаходзится гдзе-небудзь у вашай дрэве компанентаў, яго код таксама знаходзится у вашым бандле.

Гэта стварае жорсткі компроміс: дадатковыя компаненты збільшуююць размер вашага JavaScript-пакета. Большы пакет удзельна збільшвае час, патрэбны для стварэння інтерактыўнасці. У практыцы вы ў канечнай лініі доставляеце код у браузеры, якія ніколі не мелі прычыны яго выканаць.

Проблема «водныя спады»

Даўнае рашэнне для компанентаў сервера было такім, што кожны компонент, якому патрабаваліся даны, мусеў іх запрашваць пасля таго, як дастаўся кліенту. Тыповы патэрн заключаўся у адобразэнні тымчасовага шэлка, запуску useEffect, чаканні на адпаведзь і толькі пасля чаго — адобразэнні рэальнага кантэнту. Якщо гэты кантэнт залучаў вярстаны компонент, які таксама патрабаваў сабе даных, цыкл павтарываўся: ўсё той самы эфект, ўсё тое ж чаканне, ўсе тыя ж затрымкі, якія дадаваліся да пакананых. Гэта ланцоўка рэакцый называецца «водоспадам запрашання даных», і гэта пояснюе, чаму багатыя прыклады застосоў React здаюцца медленнымі, нават калі ўсе бэкенд-API-яўы адпаведзаюць быстра.

Адзін з спосабаў абходжання гэтай проблемы быў перанесенне процэса запрашання дадзейнаў на рэвень маршрута за дапамой такіх інструментаў, як getServerSideProps або ладчыкі маршрутаў, але гэта каралася пакутніцамі: гэта нарабляла прычыны для парадуку самастойнай натуры компанентав. Раптам стораніца пачала трэбаваць дадзейнаў, якія концэптуальна належалі да ёе дзецячых компанентав, і компаненты перасталі быць незалежнымі елементамі.

Пакутніцы гідратацыі

Традыцыйны серверны спосаб адрасавання працюе так: на серверы генеруецца HTML, яны адправляюцца на кліента, а пасля весь прыемлік перадаецца на перадрукаванне на кліянтскай стороне за дапамой JavaScript, ў результаты чаго стае інтэрактывным. Гэта значыць, што кожны компанент, включаючы тыя, якім ніколі не будзе патрэбна кліянтская логіка, все рава павінен пройсці процэс гідратацыі. Па суті, вы плаціце пакутніцы за інтэрактывнасць нават для контента, які ў цэлым є статычным.

React Server Components рашае ўсі тры гэтыя проблемы на архітектурнам роўні, а не як частковы патч для падвышэння карыстоўнасці.

Ментальная модэль: Server Components — гэта не „SSR 2.0“

Гэтае ўсходнай ідея, на якой стоіць весь гэты практычны кярэн: Server Components — гэта не спосаб атрыбутавання сторунак. Це аднае категорыя компонентаў.

Класічны React вядомаў толькі аднаго роду компонент. Ён выкананы ў браўзеры. Ён могаў хаваць стан, запускать эфекты і рэагаваць на здарэння. Усі ўжыткі жыцця такога компонента, ад стварэння да знишчэння, відбываліся на стороне кліента.

React Server Components дадаюць другую катэгорію. Серверны компонент выкананы на сервере. Ён можа без працы запускаць работы з файлавой системай, выконваць запыты да базы дадзеных безпосередна або выкарыстоўваць бібліятэкі, якія працуюць толькі ў Node.js. Але ён не можа выкарыстоўваць useState, useEffect чы прыўязваць обрабнікі змян, таму што ён проста ніколі не выкананы у браузере. Для яго няма крока гідратацыі. Його код ажнай не перадаецца кліенту у вачынку JavaScript.

Прыемны спосаб працавання з гэтым: дрэва компонентаў React тепер є складным. Адзіныя галузі генеруюцца на сервере, іншыя — у браузере. Галузі з сервера выкананы роўна адназначна, пад час запыту, а тое, што яны ствараюць, перадаецца кліенту у вачынку серыяваных элементаў React. Галузі з кліента выкананы у браузере як зазвичай і захоўваюць усія інтэрактывныя можлівасці, да якіх вы прыzwyczайаны.

Это іншы механізм, чым SSR. Server-side rendering адрабатвае цэлую прыемку на серверы і ператварае яе ў HTML, а пасля знову запускае ў браузеры. У працоўны час RSC адрабатвае толькі пэўныя компаненты на серверы і ніколі не перадае ў браузеры ях код.

Што на самай працоўны час перадаецца кліенту

Калі серверны компанент адрабатваецца, ён не выдае HTML. У замене ён стварае серыяваўшыяся апісанні своего выходу, вядомыя як RSC Payload — струмэн інструкцый, сэродзеўных JSON, якія паведамляють React у кліентскай частцы, як скласіць дрэво, якое трэба адобразіць.

Усё, што вядзецца за кулісамі, калі запрашваецца сторанка, якая мае серверныя компаненты:

  1. React адрабатвае серверныя компаненты на серверы.
  • Для кожнага серверскага компонента ён выдае фактычны адразаваны выхід — створеныя элементы, а не код-выкладчык, які іх створыў.
  • Для кожнага кліентскага компонента ён выдае замест таго кансэкт: маркер, який паказывае, дзе трэба размістіць гэты компонент, а таксама параметры, якія ёму патрэбны.
  • Сервер передае весь гэты пакет дадзеных да браузера.
  • Рэантайм React у браузеры парсуе гэты пакет і стварае атрыбутную дрэва.
  • Кліентскія компоненты пасля чаго завантажваюць свой код і адразаваюця. Серверскія компоненты, якія вже былі адразаваны, не патрабуюць жадных крокаў адразавання.
  • Ключовым вывадам яе тое, што код серверных компанентаў ніколі не патрапляе ў пакет JavaScript, які адправляецца да браузераў. Уявіце сабе компанент MarkdownRenderer, створанный на базе бібліятэкі для парсінгу Markdown размерам 200 КБ. Якшто гэты компанент ўжо серверны, уся бібліятэка размерам 200 КБ застаецца на серверы. Браузер бачыць толькі структуру, яку створыў парсер, а не сам парсер.

    Гэтае і є сутністю тверджэння пра абсолютна малы размер пакета, і гэта не проста техніка оптымізацыі. Гэта справжняя змена ў там, што на самае працэ пабудовы дапраўкі на React фактычна паўтараецца.

    Граніцы сервера і кліента

    У App Router кожны файл лічыцца як Server Component, якщо толькі не зазначана іншая прыметка. Гэта не проста стылістычная стандартна практыка — гэта структурны прынцып, закладзены ў фрэймворк, який відбівае ідею пра тое, што большая частка вашага інтерфейсу вовсе не патрэбна для роботы ў браузеры.

    Кліентскі компонент, на протывару, — цэў код, які павінен выконвацца на комп’ютеры корыстувальніка. Файл пазначаецца як кліентскі, размістыўшы ў його верхней частцы дырэктыву "use client". Гэта не проста рекамендацыйны тэкст — гэта жорсткая межа. Яна інструктуець компілятор React пра тое, што все, што визначанае ў гэтым файле, а таксама все, што яны імпортуецца, павінна быть запакована і доставлена ў браузер.

    Правілле, якое парадоксальна гэты весь систему, такое: компаненты сервера могу без працы імпортуваць і адрасаваць компаненты кліента, але зворачны варыянт ніколі не дазволены — компанент кліента не можа імпортуваць компанент сервера.

    На першы погляд гэта здаецца некальканосным. Чы не должны коды сервернай стороны быць доступныя з будзь-яго месца, укладаючы і файлы кліента? Не зовсім, як толькі разумееш, як на самае працоўваюць даны:

    • Спачатку выконваецца компанент сервера, який мае прымітны доступ да вашай базы дадзеных і ресурсаў бэкенду. Ён запрашвае неабходныя даны і стварае макет. У гэтым макете ён можа адрасаваць ўжо ў формате <UserProfile />, для чаго патрэбна інтерактыўнасць — таму такі фрагмент пішаецца як компанент кліента. Компанент сервера-родзіцель перадае запрашаныя даны користувальніка як параметры.
  • Компанента кліента проста ўжывае гэтыя параметры і адрасавае інтэракtyўныя часткі. У яё немае можлівасці звярнуцца назад і запрашаць компанент сервера, таму што калі ён запускаецца ў браузеры, выкананне на стороне сервера вялікі час яўна завершылася. Не застаёцца жаднага серверскага процесу, які можна было б запрашаць.
  • Самэй таго такая структура не можа працаваць:

    // ❌ Impossible: Client Component importing Server Component
    'use client';
    import { ServerDataFetcher } from './ServerDataFetcher'; // This breaks!
    export function ClientWidget() {
      return (
        <div>
          <ServerDataFetcher /> {/* Cannot render a server component here */}
        </div>
      );
    }
    

    Але структураванне рэчаў іншым спосабам ёсць абсалютна дапустжым:

    // ✅ Correct: Server Component importing Client Component
    // This is a Server Component (no 'use client')
    import { ClientWidget } from './ClientWidget';
    async function ServerDataFetcher() {
      const data = await db.query('SELECT * FROM posts');
    
      return (
        <div>
          <h1>Latest Posts</h1>
          {data.map(post => (
            <ClientWidget key={post.id} post={post} />
          ))}
        </div>
      );
    }
    

    Шаблон просты: компанента сервера адпавядае за запрашэнне дадзеных і структурнае адрасаванне, пасля чаго перадае дадзеныя інтэракtyўным компанетам, якія знаходзяцца на канчыках „дрэва“. Гэтыя компанеты адпавядаюць за клікі, выкананне форм і анімацыі. Рэзультатныя архітектуры па суты ёсць „дрэвамі“, адрасаванымі на серверы, з элементамі інтэрактыўнасці, распаўзлымі ў яго канцах.

    Асінхронныя компанеты: Рэвалюцыя у запрашэнні дадзеных

    Класычныя компоненты React ніколі не дазволялі функцыям компонентаў быть асінхроннымі. Запіс await безпасэродзе ў тэле компонента не была можлівасцю — трэба было выкарыстоўваць useEffect і вручную кераваць станам завантажэння.

    Компоненты сервера скасоўваюць гэтыя обмежэння: яны можуць быть async. Гэта выглядае як незначны синтаксічны дадатак, але ён значна пераформатавае адпоўную архітэктуру.

    // ✅ Server Component: Direct data access, no useEffect
    async function BlogPostList() {
      // This runs on the server. No fetch call in the browser.
      const posts = await db.post.findMany({
        orderBy: { createdAt: 'desc' },
        take: 10
      });
    
      return (
        <ul>
          {posts.map(post => (
            <li key={post.id}>
              <h2>{post.title}</h2>
              <p>{post.excerpt}</p>
            </li>
          ))}
        </ul>
      );
    }
    

    Зверніце ўвагу на все, чаго тут няма. Няма useState для стежэння за флагам завантажэння, няма useEffect для запуску запыту, няма вручную створанага экрана-скелета. Компонент проста перадае записы з базы дадзенаў безпасэродзе ў элементы React. Запыты тепер выкананыя ў кожным компоненте окрема, а не па кожнай маршруту, і ўсе гэта відбываецца абоўсюды на серверы, ніколі ў браузеры.

    З-за гэтаго проблема з водападамі зникае — сервер можа адразу обрабатваць кожны асінхронны компанент паралельна, прычым не падаючы адказ кліенту. Запыты да базы дадзеных выконваюцца ў там самым центре дадзеных, што і ваш бэкенд, таму затрымка мерыцца ў мікросекундах, а не у мілісекундах, якія звычайна буваюць пад час перавагоў через мобільны з’яўленне.

    Дырэктыва “use client”: калі і чаму

    Дадаць "use client" означае, што файл належыць до средовышча браузера. Яго неабходна ўсё тады, калі компанент працуе з чымось, што ўласна належыць да кліентскай часткі:

    • Локальны стан за дапамогою useState або useReducer
    • Хукі жыцёвага циклу, такія як useEffect або useLayoutEffect
    • Обробка здарэнняў, напрыклад onClick або onSubmit
  • Апіі прыгледача — localStorage, window, document
  • Хукі, які зв’язаны з контэкстам прыгледача, уключаючы певныя варыянты викорыстоўвання useRouter чы useMediaQuery
  • Частая памылка — размешчанне гэтага напамінання занадта высока ў дрэве компонентаў. Разработчыкі часта ператвараюць цэлую сторанку на кліентскі компонент толькі таму, што аднай вбудованай кнопцы патрэбна інтерактыўнасць.

    // ❌ Bad: Making the whole page client-side for one interactive element
    'use client';
    import { useState } from 'react';
    import { HeroSection } from './HeroSection'; // Static, could be server
    import { LikeButton } from './LikeButton';   // Interactive, needs client
    export default function Page() {
      return (
        <div>
          <HeroSection />
          <LikeButton />
        </div>
      );
    }
    

    У гэтым фрагменте HeroSection ўсё ж такі ўсунуты статычны маркап, які мог бы працаваць праз сервер. Але так как "use client" было заявлена на рэбёнку, кожны імпорт пад яй — уключаючы гэты статычны раздзіл — адносна пакуецца і надаецца прыгледачу.

    Рашэнне: Перамесціце "use client" нижэй у дрэве

    Рашэнь — гэта заставіць саму сторанку выступаць як серверны компонент, а інтэрактыўную частку — як лістоўскі вузол, які імпортуецца ў яго.

    // ✅ Good: Page is server, only LikeButton is client
    // page.tsx (Server Component by default)
    import { HeroSection } from './HeroSection';
    import { LikeButton } from './LikeButton';
    export default function Page() {
      return (
        <div>
          <HeroSection />
          <LikeButton postId="123" />
        </div>
      );
    }
    
    // LikeButton.tsx
    'use client';
    import { useState } from 'react';
    export function LikeButton({ postId }) {
      const [liked, setLiked] = useState(false);
    
      return (
        <button onClick={() => setLiked(!liked)}>
          {liked ? '❤️' : '🤍'}
        </button>
      );
    }
    

    За такой структурой ні HeroSection, ні Page не выкладзяцца ў браузер у формате JavaScript. Толькі LikeButton, а таксама вызов useState у яго, прабывае на кліентскай стороне. Гэта і є практычны механізм, які дапамагае досягнуць меты нульовага розмеру пакета: як магчыма больш часткі дрэва компонента застаецца на сервере, а кліентская сторона выкорыстоўваецца толькі для тых вузлаў, якім дасканалі інтэрактыўнасць.

    Інтэрлейвінг: патэран, які робіць RSC моцным

    Тэхніка, яка надаеўць RSC справжняй сілы, — это перакладчыкаванне: размешчэнне серверных складовых усередине кліентскіх складовых, перадача дадзейнаў, отрыманых з сервера, як параметраў, і дазвол чырвоным складовым выклікваць слоты children, якія можу прымець ўсё больш серверных складовых.

    // Layout.tsx (Server Component)
    import { Sidebar } from './Sidebar';
    import { AnalyticsProvider } from './AnalyticsProvider';
    export default async function DashboardLayout({ children }) {
      // Fetch user data on the server
      const user = await getCurrentUser();
      const permissions = await getUserPermissions(user.id);
    
      return (
        <div className="dashboard">
          <Sidebar user={user} permissions={permissions} />
    
          {/* AnalyticsProvider is a Client Component */}
          <AnalyticsProvider userId={user.id}>
            {/* children here can be a Server Component page */}
            <main>{children}</main>
          </AnalyticsProvider>
        </div>
      );
    }
    
    // AnalyticsProvider.tsx
    'use client';
    import { createContext, useContext } from 'react';
    const AnalyticsContext = createContext(null);
    export function AnalyticsProvider({ userId, children }) {
      // Client-side analytics initialization
      useEffect(() => {
        analytics.identify(userId);
      }, [userId]);
    
      return (
        <AnalyticsContext.Provider value={{ userId }}>
          {children}
        </AnalyticsContext.Provider>
      );
    }
    

    У гэтым прыкладзе DashboardLayout работае на сервере і безпасэродна запытае базу дадзейнаў. Ён перадае гэтыя даны ў Sidebar, які сам можа быць серверной або кліентскай складовой залежна ад сваіх патрэб. Кроме таго, ён абгортае рэшту старонкі ў AnalyticsProvider, кліентскую складовую, неабходную ў браузеры для запуску бібліятэкі аналітыки трохцях сторонніх выдавачаў.

    Важным элементам ёсць атрыбут children. Усё, што выводзится ўнутрь AnalyticsProvider, не павінна стаць кодам кліента толькі таму, што яна знаходзится там. React передае вярнуўшыся з сервера выход дадзення Компонента сервера через Компонент кліента як children — Компонент кліента проста выступае як обгортка або межа, а не як перакладчык, який змушвае ўсё, што знаходзится ўнутрь яго, працаваць на боку кліента.

    Самэй такі патэрн будуецца гібрыдныя інтерфейсы: контэнт, выведзеный на сервере, знаходзится ўнутрь обгортак кліента самэй там, дзе практычна неабходныя взаімадзейнасці.

    Пакет дадзення RSC: пагляд унутрь

    Выведзенне Компонента сервера не стварае HTML безпосередна. У замен React выдае пакет дадзення RSC — бінарны стрым, які концэптуальна нагадвае гэта:

    1:I["node_modules/react/jsx-runtime.js", "jsx"]
    2:I["./components/ClientWidget.js", "default"]
    0:["quot;, "div", null, {"children": [
      ["quot;, "h1", null, {"children": "Latest Posts"}],
      ["quot;, "@2", null, {"postId": "123", "title": "Hello World"}]
    ]}]
    

    Кожны лінійкі ў гэтым стрымені являе сабою інструкцыю. Сімвал $ пазначае элемент React. I абзначае імпорт модуля кліентскага компонента. Адреса на кшталт @2 паказывае на другі імпорт — у гэтым случыку ClientWidget. Заўважкайце, што сервер уже цалкам адрасаваў тэг h1, але для ClientWidget ён толькі перадаў пропсы і паказаў, дзе знаходзіцца яго код, не адрасаваючы його самога.

    Калі браузер прыме гэты стрым, ён разв’язвае тыя згадкі пра імпорт, запрашоўвае неабходныя пакеты кліентскіх компанентаў і складае гэтакі канечны дрэво компанентаў. Паколькі даны прыходзяць паэтапна, браузеру не трэба чакаць на ўсё, прычым я ўжо пачынае адрасаваць іх. Самэ гэта паэтапна доставленне дазволяе тэхналогіі RSC падтрымляць стрыменаванае адрасаванне з боку сервера, ухіліваючыся ад звычнага бутлачэна ў процесе ініцыялізаціі.

    Кэшаванне і паўнапрацэсная пераправерка

    Next.js 15 і новейшыя версіі даўаюць серверскім компанентам доступ да всей сяроды кэшавацкіх стратэгій:

    1. Статычнае адрасаванне (стандарт). Як толькі компанент не чытае дынамічныя даны або не выканае запрашэнне, якае не кэшуецца, ён адрасаваецца статычна пад час стварэння проекта.
    // Cached indefinitely at build time
    async function ProductList() {
      const products = await fetch('https://api.example.com/products');
      // ...
    }
    
    1. Дынамічная выкладка. Выклік функцый cookies(), headers() чытачка значэння з searchParams, або явна настройка export const dynamic = 'force-dynamic' прымушвае компонент выкладывацца з кожным новым запитам.
    2. Паўтарная пераверкі за дапамою таймера.
    // Revalidate every 60 seconds
    async function ProductList() {
      const products = await fetch('https://api.example.com/products', {
        next: { revalidate: 60 }
      });
      // ...
    }
    
    1. Паўтарная пераверкі запускаецца за патрэбай.
    // app/api/revalidate/route.ts
    import { revalidatePath } from 'next/cache';
    export async function POST() {
      revalidatePath('/products');
      return Response.json({ revalidated: true });
    }
    

    Галоўны вынік — аднаразовая кешавання тепер прылягае да адзінаковых компонентоў, а не да цэлых маршрутаў. Два компоненты, якія знаходзяцца на адной сторонце, можу следаваць абсалютна разным правілам кешавання. Такая дзеярганізацыя не мае адпаведніка ў класычным SSR, дзе адна кешавальная заголовочная пара керуе цэлай сторонкою адразу.

    Пастойныя непрацоўкі

    «Компаненты сервера існуюць галоўная метай для SEO». Не зовсім — кращая індексацыя пошуку є пасляэфектам, а не метай. Асалодны мотывацый — зменшыць викорыстоўванне JavaScript на боку кліента і дазволіць загрузкі дадзеных на рэвэле компанента.

    «Кожны компанент, які викорыстоўвае хук, патрабуе use client.» Гэта правда толькі тады, калі хук фактычна залежыць ад API прыгледача. Хук use у React 19 можа распакаваць прамісы і чытаць контэкст безпосередна ўнутрь компанентаў сервера, таму багато хуков працуюць нормальна, не тыкнуўшыся ў кліента.

    «Компаненты сервера робяць марнымі шляхі API». Яны так не робяць — гэтыя два элементы працуюць разам. Компаненты сервера беруць на сябе задачу загрузкі дадзеных пад час першага атрыбутавання, але вам все рав трэбаюць шляхі API, каб обрабатваць мутацыі, прыходзячыя вебхукі з трэціх сторон і будзь-якія загрузкі, якія выконваюцца на боку кліента пасля гідратацыі.

    «Компаненты сервера не маюць стану». У іх няма стану у стылі браузера — няма доступнага useState — але яны можуць свабодна з’яўляцца да істочнікаў стану на серверае, такіх як базы дадзеных, кэшы, файлавая система і змянныя сераўісу.

    «Контэкст забаранены ў компанентах сервера». Вы сапраўды не можете выкарыстоваць React Context унутрь компаненту сервера, адколі Контэкст існуе саме для таго, каб утрымацься ад передачы пропаў па вершыні дрэва компанентоў, якія рендаруюцца на кліеантэ. У замен вы можете перадаваць даны як звычныя пропы, і адтуды, што рендараванне на серверае сінхронна разв’язвае дрэва компанентоў зверху вярху, Next.js таксама праставляе такія можлівасці, як unstable_rootParams, паўступаючы да звычайнай передачы пропаў.

    Стан рэчаў на 2026 год

    Тепер, калі React 19 стаў стабільным, супакоўкі, якія з’яўляюцца ўсяго ўжо, значна вырасілі:

    • Функцыі сервера дазволяюць компонентам кліента запускать асінхронныя функцыі, якіе выкананы безпасу на сервере, чым смягчаецца межа між кліентам і серверам пад час выканання змян.
    • Хук use дае компонентам кліента можлівасць распакаваць прагнення і контэкст без неабяжнае выкарыстання useEffect.
    • Частковая прадзейнаванне (PPR) у Next.js 15 дазволяе выдаваць статычную частку безпасу з CDN, тады калі дынамічныя часткі завантажаюцца з основнага сервера.
    • Кампіляр React аўтаматычна керуе мемаізацыяй компонентам кліента, зменшваючы колькасць ручных вызоваў useMemo і робячы пераход між серверам і кліентам болей плавным.

    Канцэптуальная модель на гэтам момент стабілізавалася. Компаненты сервера больш не ўважаюцца функцыяй, якую можна актываўаць выборча — ўсё больш яны є базовым прыняццем для стварэння сучасных застосоў на React. Компаненты кліента тепер ёсць аднаковаючымся правілам: це спецыяльны механізм, прызначанный для інтэрактыўнага шару.

    Змена ў архітэктуре, а не толькі ў выдатнасці

    Компаненты сервера React — гэта не проста прабаўка ў падышчу выдатнасці. Яны вяскроўваюць перэосмысленне таго, дзе на самай працоўвае код React. Прыблізна дзесять гадоў React быў фундаментальна браузерным кітэнгам, які быў адаптаваны для роботы на серверае галоўная для задоволення трэбаванняў SEO. Сёньдзе ён стаў чымось іншым: цэлысткім системай компанентаў, якая працуе на обох канцах сетевага з’ўязку, пры чым кожны з яе элементаў мае чыста визначаныя межы, адпаведальнасці та показнікі выдатнасці.

    Сервер большэй не ўжо проста месца для запрашання дадзейнаў — ён тепер являе сабою практычнае сераўскае абёртанне. А браузер большэй не ўжо едынственны месца для компанентаў React; натоўп, самэ гэтае месца, дзе выклікаецца інтэрактыўнасць.

    Калі гэтае розумеўне стане ясным, большая частка плутання ўжо не будзе асаблівай прычыной. Пытанне пераходзіць з "Чы трэба тут вжываць use client?" на "Дзе па праву апісваецца гэты конкрэтны фрагмент логіки?" Гэтае пытанне вартуе задаць, і гэты падход дапамагае растуць разам з прыемліваннямі.

    Спадневаная літэратура

  • Пераход ад CSS-in-JS у часе выконання: серверныя компаненты і стылі часу будовы — чаму CSS-in-JS у часе выконання суперсечаецца з сервернымі компанентамі React і цілямі ў паўнэй канцэртнасці, як поручаюцца Tailwind, CSS Modules і бібліятэкі без выкарыстоўвання ресурсаў у часе выконання, і як безпечна перайсці на іншы падход.