React Compiler у 2026 році: автоматична мемоїзація та питання для співбесід

Повний огляд React Compiler — автоматична мемоїзація, конвеєр компіляції, правила React, інтеграція з ESLint та питання для технічних співбесід з React у 2026 році.

React Compiler автоматична мемоїзація та питання для технічних співбесід у 2026 році

React Compiler у 2026 році досяг стабільної версії 1.0, ставши частиною стандартного інструментарію React 19. Цей інструмент автоматично аналізує компоненти та хуки на етапі збірки, додаючи мемоїзацію обчислень, JSX-елементів та колбеків без будь-якого втручання розробника. Для проєктів, що раніше покладалися на ручне використання useMemo, useCallback та React.memo, компілятор усуває цілу категорію помилок продуктивності та спрощує кодову базу. Розуміння принципів роботи React Compiler є обов'язковою компетенцією для frontend-розробників, які готуються до технічних співбесід у 2026 році.

Ключовий факт для співбесіди

React Compiler аналізує код на етапі збірки та автоматично додає гранулярну мемоїзацію на рівні окремих виразів. Він не змінює семантику програми — лише пропускає повторні обчислення, коли залежності не змінились. Компілятор працює за умови дотримання "Rules of React": чисті render-функції, відсутність мутацій пропсів та стану під час рендерингу.

Що таке React Compiler та як він оптимізує код

React Compiler — це плагін для Babel, який трансформує компоненти та хуки на етапі збірки. На відміну від runtime-оптимізацій, компілятор аналізує потік даних у кожному компоненті, визначає залежності кожного виразу та автоматично огортає обчислення у кеш. Результат компіляції використовує внутрішній хук useMemoCache, який зберігає проміжні значення між рендерами.

Принциповою відмінністю від ручної мемоїзації є гранулярність. Розробник, що використовує useMemo, мемоїзує цілі блоки обчислень. Компілятор оперує на рівні окремих виразів: якщо змінився лише user.firstName, перерахується тільки fullName, тоді як style залишиться кешованим. Такий підхід забезпечує оптимальну мемоїзацію, яку людина-розробник рідко реалізує вручну через непрактичність.

javascript
// Before compilation
function UserProfile({ user, theme }) {
  const fullName = user.firstName + ' ' + user.lastName;
  const style = { color: theme.primary, fontSize: 16 };
  return <div style={style}>{fullName}</div>;
}

// After compilation (simplified representation)
function UserProfile({ user, theme }) {
  const $ = useMemoCache(4);
  let fullName;
  if ($[0] !== user.firstName || $[1] !== user.lastName) {
    fullName = user.firstName + ' ' + user.lastName;
    $[0] = user.firstName;
    $[1] = user.lastName;
    $[2] = fullName;
  } else {
    fullName = $[2];
  }
  // style and JSX similarly memoized...
}

Масив useMemoCache виступає локальним кешем компонента. Кожен слот зберігає або залежність, або обчислене значення. Перед кожним обчисленням компілятор перевіряє, чи змінились залежності. Якщо вхідні дані ідентичні попереднім, повертається кешоване значення без повторного обчислення. Цей механізм працює для примітивних значень, об'єктів, JSX-елементів та функцій-колбеків.

Конвеєр компіляції: сім фаз трансформації

React Compiler виконує трансформацію коду через послідовність з семи фаз, кожна з яких відповідає за конкретний аспект аналізу та оптимізації.

Фаза 1: Парсинг та побудова AST. Вхідний JavaScript/TypeScript код перетворюється на абстрактне синтаксичне дерево (AST) через інфраструктуру Babel.

Фаза 2: Побудова HIR (High-level Intermediate Representation). AST трансформується у високорівневе проміжне представлення, яке зберігає структуру React-компонента: хуки, JSX, умовні гілки, цикли.

Фаза 3: Аналіз залежностей. Компілятор визначає, які змінні залежать від яких вхідних даних. Для кожного виразу будується граф залежностей, що відстежує зв'язок від пропсів та стану до проміжних обчислень і JSX-виводу.

Фаза 4: Перевірка Rules of React. Компілятор валідує, що компонент дотримується правил React: чистота render-функції, відсутність мутацій пропсів, правильне використання хуків. Компоненти, що порушують правила, пропускаються без оптимізації.

Фаза 5: Побудова реактивних блоків. На основі графу залежностей код розбивається на реактивні блоки — групи виразів з однаковими залежностями, які можуть бути мемоїзовані разом.

Фаза 6: Генерація мемоїзованого коду. Кожен реактивний блок огортається в умовну перевірку залежностей з використанням useMemoCache. Компілятор генерує оптимальну кількість слотів кешу.

Фаза 7: Генерація вихідного JavaScript. Оптимізоване проміжне представлення перетворюється назад у валідний JavaScript, готовий до виконання.

Весь процес відбувається під час збірки та не впливає на розмір бандлу або час виконання. Єдиний runtime-артефакт — виклики useMemoCache, що додають мінімальний overhead у вигляді масиву кешу на кожен компонент.

Правила React, які передбачає компілятор

React Compiler базується на припущенні, що код дотримується "Rules of React" — набору інваріантів, які забезпечують передбачувану поведінку компонентів. Порушення цих правил призводить до того, що компілятор або пропускає компонент без оптимізації, або генерує некоректний код.

Чистота render-функції. Render-функція компонента повинна бути чистою: для однакових пропсів та стану вона повинна повертати однаковий JSX. Побічні ефекти (зміна DOM, HTTP-запити, запис у localStorage) дозволені лише в обробниках подій та ефектах (useEffect).

Заборона мутацій пропсів та стану. Пропси та стан є незмінними під час рендерингу. Мутація масиву пропсів, зміна об'єкта стану напряму або модифікація ref.current під час рендерингу — все це порушення, які компілятор детектує.

Правила хуків. Хуки викликаються лише на верхньому рівні компонента, не всередині умов, циклів чи вкладених функцій. Порядок виклику хуків повинен бути однаковим при кожному рендерингу.

javascript
// Rule violation: mutating during render
function BadCounter({ items }) {
  // The compiler will skip this component
  items.sort(); // Mutates the prop array!
  return <ul>{items.map(i => <li key={i}>{i}</li>)}</ul>;
}

// Correct: create a new sorted array
function GoodCounter({ items }) {
  const sorted = [...items].sort();
  return <ul>{sorted.map(i => <li key={i}>{i}</li>)}</ul>;
}

У прикладі BadCounter виклик items.sort() мутує масив, переданий як проп. Компілятор визначає це порушення та пропускає компонент, залишаючи його без оптимізації. У GoodCounter оператор spread [...items] створює копію масиву, після чого сортування виконується на копії. Цей компонент є чистим і буде успішно оптимізований компілятором.

Компілятор пропускає, а не ламає

Коли React Compiler виявляє порушення правил, він не генерує помилку збірки. Замість цього компонент виключається з оптимізації та працює без мемоїзації, як до впровадження компілятора. Це забезпечує безпечне поступове впровадження, але означає, що невиявлені порушення залишаються прихованими проблемами продуктивності.

Інтеграція з ESLint: виявлення порушень на етапі розробки

Плагін eslint-plugin-react-hooks доповнює компілятор, виявляючи порушення Rules of React на етапі написання коду. Рекомендована конфігурація включає набір правил flat.recommended, сумісний з новим форматом ESLint flat config.

eslint.config.jsjavascript
import reactHooks from 'eslint-plugin-react-hooks';
import { defineConfig } from 'eslint/config';

export default defineConfig([
  reactHooks.configs.flat.recommended,
]);

Плагін перевіряє правила хуків (порядок виклику, заборона умовних хуків), залежності useEffect та useMemo, а також базові порушення чистоти компонентів. Варто зазначити, що ESLint не покриває всі правила, які перевіряє компілятор. Компілятор виконує значно глибший статичний аналіз потоку даних, який неможливо повністю реалізувати на рівні ESLint-правил.

Для проєктів, що впроваджують React Compiler, рекомендовано активувати ESLint як перший бар'єр захисту. Порушення, виявлені ESLint, слід виправляти до запуску компілятора — це прискорює цикл розробки, оскільки помилки ESLint видно безпосередньо в редакторі, без необхідності запускати збірку.

Коли ручна оптимізація залишається необхідною

React Compiler автоматизує переважну більшість сценаріїв мемоїзації, але певні категорії оптимізацій залишаються поза його зоною відповідальності.

Ресурсомісткі обчислення з великими наборами даних. Компілятор мемоїзує результат, але не оцінює обчислювальну вартість. Якщо масив rows містить 10 000 елементів, а heavyTransform виконує складну операцію на кожному, ручний useMemo з явною залежністю [rows] залишається доцільним для документування наміру та забезпечення передбачуваності.

Інтеграція з зовнішніми бібліотеками. Компілятор аналізує лише код компонентів та хуків. Виклики зовнішніх бібліотек, що повертають нестабільні посилання (нові об'єкти при кожному виклику), можуть потребувати ручної стабілізації через useMemo або useRef.

Підписки та побічні ефекти. useCallback для стабілізації колбеків, переданих у useEffect як залежності, продовжує використовуватися, коли компілятор не може гарантувати стабільність посилання через складну логіку замикань.

javascript
// The compiler handles this automatically
function ProductCard({ product, currency }) {
  const formattedPrice = formatCurrency(product.price, currency);
  const discount = product.originalPrice - product.price;
  return (
    <div>
      <span>{formattedPrice}</span>
      {discount > 0 && <Badge>Save {discount}</Badge>}
    </div>
  );
}

// Manual optimization still needed: expensive external computation
function DataGrid({ rows }) {
  const processedRows = useMemo(
    () => rows.map(row => heavyTransform(row)), // O(n) with large n
    [rows]
  );
  return <VirtualList items={processedRows} />;
}

У ProductCard компілятор автоматично мемоїзує formattedPrice, discount та JSX-елементи. Ручне додавання useMemo було б надлишковим. У DataGrid ручний useMemo залишається виправданим: він документує намір розробника щодо ресурсомісткої операції та слугує захисним механізмом, навіть якщо компілятор додасть власну мемоїзацію.

Готовий до співбесід з React / Next.js?

Практикуйся з нашими інтерактивними симуляторами, flashcards та технічними тестами.

Підключення React Compiler у різних фреймворках

React Compiler інтегрується через систему плагінів збірки. Конфігурація залежить від використовуваного фреймворку та бандлера.

Next.js

Next.js надає вбудовану підтримку React Compiler через прапор experimental.reactCompiler. Цей прапор активує Babel-плагін компілятора для всіх файлів проєкту без додаткової конфігурації.

next.config.jsjavascript
const nextConfig = {
  experimental: {
    reactCompiler: true,
  },
};
export default nextConfig;

Vite

Для проєктів на базі Vite необхідно підключити Babel-плагін через @rolldown/plugin-babel. Пресет reactCompilerPreset включає всі необхідні налаштування трансформації.

vite.config.jsjavascript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import babel from '@rolldown/plugin-babel';
import { reactCompilerPreset } from 'babel-plugin-react-compiler';

export default defineConfig({
  plugins: [
    react(),
    babel({ presets: [reactCompilerPreset] }),
  ],
});

Для обох конфігурацій рекомендовано використовувати React 19 або новіший. Компілятор генерує код, що залежить від runtime-хука useMemoCache, доступного починаючи з React 19. Для проєктів на React 17 або 18 необхідно встановити пакет react-compiler-runtime, який надає поліфіл для useMemoCache.

Поступове впровадження

React Compiler підтримує поступове впровадження: можна обмежити його дію конкретними директоріями або файлами через конфігурацію Babel. Це дозволяє активувати компілятор для нових компонентів, одночасно залишаючи старий код без змін, та поступово розширювати охоплення після валідації.

Порівняння: React Compiler та ручна мемоїзація

| Аспект | React Compiler | Ручна мемоїзація (useMemo/useCallback) | |---|---|---| | Гранулярність | На рівні окремих виразів | На рівні блоків, визначених розробником | | Вимагає втручання розробника | Ні, працює автоматично | Так, вимагає явного обгортання | | Ризик забутої мемоїзації | Відсутній | Високий — поширена причина проблем продуктивності | | Ризик зайвої мемоїзації | Мінімальний, компілятор оцінює доцільність | Високий — передчасна оптимізація засмічує код | | Залежності | Визначаються автоматично через аналіз потоку даних | Задаються вручну, помилки у масиві залежностей призводять до багів | | Складність коду | Не додає складності, код залишається чистим | Збільшує когнітивне навантаження та кількість коду | | Обробка порушень | Пропускає компонент без оптимізації | Не перевіряє правила, може маскувати помилки | | Підтримка ресурсомістких обчислень | Мемоїзує, але не оцінює вартість | Розробник явно визначає критичні обчислення | | Сумісність зі старим кодом | Вимагає React 19+ або поліфілу | Працює з React 16.8+ |

Типові питання для технічних співбесід

Питання щодо React Compiler стали стандартною частиною технічних співбесід для React-розробників у 2026 році. Нижче наведено найпоширеніші запитання та очікувані відповіді, що допоможуть у підготовці до інтерв'ю з React та Next.js.

Що таке React Compiler і чим він відрізняється від runtime-оптимізацій? React Compiler — це плагін для Babel, що аналізує компоненти на етапі збірки та автоматично додає мемоїзацію. На відміну від React.memo та useMemo, які працюють під час виконання, компілятор виконує статичний аналіз потоку даних та генерує оптимізований код до того, як він потрапить у браузер. Це усуває runtime-overhead на визначення залежностей.

Чи потрібно видаляти існуючі useMemo та useCallback після увімкнення компілятора? Ні, існуючий код з ручною мемоїзацією продовжить працювати коректно. Компілятор розпізнає ці конструкції та інтегрує їх у свою систему кешування. Поступове видалення ручної мемоїзації є рекомендованим для спрощення коду, але не є обов'язковим.

Які правила React повинен дотримуватись код для коректної роботи компілятора? Три основні правила: компоненти та хуки повинні бути ідемпотентними (однакові вхідні дані — однаковий результат), заборонено мутувати пропси та стан під час рендерингу, хуки повинні дотримуватись правил виклику (верхній рівень, сталий порядок). Порушення цих правил призводить до пропуску компонента без оптимізації.

Що відбувається, коли компілятор виявляє порушення правил? Компілятор пропускає компонент і залишає його без оптимізації. Збірка завершується успішно, помилка не генерується. Це забезпечує безпечне впровадження, але вимагає моніторингу через ESLint та інструменти аналізу для виявлення непокритих компонентів.

У яких випадках ручна мемоїзація залишається доцільною навіть при увімкненому компіляторі? Ручний useMemo виправданий для ресурсомістких обчислень з великими наборами даних, де необхідно явно документувати обчислювальну вартість. Також для стабілізації посилань на об'єкти, що передаються у зовнішні бібліотеки, які не знаходяться під контролем компілятора.

Як React Compiler впливає на розмір бандлу? Компілятор додає виклики useMemoCache та умовні перевірки залежностей, що незначно збільшує розмір згенерованого коду. Водночас видалення ручних обгорток useMemo, useCallback та React.memo компенсує це збільшення. У більшості проєктів загальний вплив на розмір бандлу є нейтральним або позитивним.

Підсумки

React Compiler трансформує підхід до оптимізації продуктивності в React-застосунках, переносячи відповідальність за мемоїзацію з розробника на інструмент збірки. Основні висновки для підготовки до технічних співбесід:

  • React Compiler аналізує код на етапі збірки через Babel-плагін та автоматично додає гранулярну мемоїзацію на рівні окремих виразів, використовуючи внутрішній хук useMemoCache
  • Конвеєр компіляції складається з семи фаз: парсинг AST, побудова HIR, аналіз залежностей, перевірка Rules of React, побудова реактивних блоків, генерація мемоїзації та фінальна генерація JavaScript
  • Компілятор вимагає дотримання Rules of React: чисті render-функції, відсутність мутацій пропсів та стану, правильний порядок виклику хуків
  • При виявленні порушень правил компілятор пропускає компонент без оптимізації, не генеруючи помилку збірки — безпечне впровадження, але потребує моніторингу через ESLint
  • Ручна мемоїзація через useMemo залишається доцільною для ресурсомістких обчислень з великими наборами даних та для стабілізації посилань при інтеграції з зовнішніми бібліотеками
  • Активація в Next.js виконується через прапор experimental.reactCompiler, у Vite — через @rolldown/plugin-babel з пресетом reactCompilerPreset
  • Існуючий код з useMemo, useCallback та React.memo продовжує працювати коректно — компілятор інтегрує ручну мемоїзацію у свою систему кешування

Починай практикувати!

Перевір свої знання з нашими симуляторами співбесід та технічними тестами.

Теги

#react
#react-compiler
#memoization
#interview
#performance

Поділитися

Пов'язані статті