Технології
React у 2026: нові примітиви (Actions, Activity, useEffectEvent) та ера Compiler
React 19 → 19.2 не просто додав фічі — він змінив те, як ми структуруємо застосунки. Цей гайд пояснює ідеї за Actions, <Activity/>, useEffectEvent, Performance Tracks, SSR Suspense batching, Partial Pre-rendering та React Compiler 1.0 — з практичними архітектурними підказками і реальними джерелами.

Що ти отримаєш з цієї статті
Це не “копія реліз-нот”. Це ментальна модель: що змінилось, навіщо воно існує і як впливає на архітектуру.
• “Чому” за новими примітивами React (менше glue-коду, більше офіційних патернів). [1][2][3]
• Коли Actions, <Activity/> та useEffectEvent — правильний інструмент (а коли ні). [1][2][6][8]
• Як Performance Tracks змінює дебаг і розмови про продуктивність. [2][5]
• Що React 19.2 змінює у SSR-стримінгу з Suspense boundary (batching). [2]
• Як React Compiler 1.0 змінює історію memoization (без “магії”). [3]
• Роадмап deep-dive статей по кожному концепту (з реальним кодом і патернами). [1][2][3]
Справжній зсув: React “продуктизує” патерни, які раніше були фольклором
React довго був як LEGO без інструкції: можна зібрати що завгодно, але кожна команда винаходила свій “правильний шлях” для async мутацій, збереження state між екранами чи уникнення багів із залежностями в effect.
React 19 і 19.2 звучать інакше. Core-команда перетворює поширені патерни на примітиви: Actions для async UI state, <Activity/> для “сховати, але зберегти state”, useEffectEvent для відокремлення event-like логіки від effect і офіційні Performance Tracks для розуміння schedulinga. [1][2][5]
А ще є React Compiler 1.0: ставка на те, що ручна memoization не має бути щоденною рутиною. [3]
Actions: зробити async UI-флоу нудним (у хорошому сенсі)
Якщо твій UI робить мутації (зберегти профіль, checkout, коментар, upload), ти, ймовірно, багато разів будував один і той самий state machine: idle → pending → success/error → optimistic UI → rollback → тости → редіректи.
Напрям Actions у React 19 намагається стандартизувати цей флоу примітивами useActionState, <form action={...}>, useFormStatus і зробити optimistic update менш болючими через useOptimistic. [1][8]
Ось маленький приклад, який показує форму цього підходу:
import { useActionState } from "react";
type SaveState = { ok: true } | { ok: false; error: string };
async function saveDisplayName(
_prev: SaveState,
formData: FormData,
): Promise<SaveState> {
const name = String(formData.get("name") ?? "").trim();
if (name.length < 2) return { ok: false, error: "Name is too short." };
const res = await fetch("/api/profile/name", {
method: "POST",
body: JSON.stringify({ name }),
headers: { "content-type": "application/json" },
});
if (!res.ok) return { ok: false, error: "Failed to save." };
return { ok: true };
}
export function DisplayNameForm({ initialName }: { initialName: string }) {
const [state, action, isPending] = useActionState<SaveState, FormData>(
saveDisplayName,
{ ok: true },
);
return (
<form action={action} className="space-y-2">
<input name="name" defaultValue={initialName} />
<button type="submit" disabled={isPending}>
{isPending ? "Saving…" : "Save"}
</button>
{state.ok ? null : <p role="alert">{state.error}</p>}
</form>
);
}Архітектурна підказка: Actions класно працює, коли mutation-флоу “належить UI” і тобі потрібен стандартний pending/result handshake без ще одного шару абстракцій. Якщо потрібні caching, retries, offline-черги або cross-screen синхронізація — часто краще підходить data layer (React Query, SWR, власний event bus). Actions зменшує boilerplate на “краях”, але не замінює системну data-архітектуру. [1][8]
<Activity />: “сховати” стає концептом першого класу
Tabbed UI, бічні панелі, wizard-и та multi-step флоу мають класичний trade-off:
- unmount коли сховано → менше пам’яті, але втрачаєш state і рвеш subscription-и
- залишити змонтованим → state зберігається, але доводиться вручну робити “hidden but alive” патерни
React 19.2 вводить <Activity mode="visible|hidden"> як альтернативу conditional rendering. У 19.2 підтримуються visible і hidden. [2]
Міні-приклад “keep alive” табу:
import { Activity } from "react";
export function SettingsTabs({ tab }: { tab: "profile" | "billing" }) {
return (
<div>
<Activity mode={tab === "profile" ? "visible" : "hidden"}>
<ProfileTab />
</Activity>
<Activity mode={tab === "billing" ? "visible" : "hidden"}>
<BillingTab />
</Activity>
</div>
);
}Архітектурна підказка: використовуй <Activity/>, коли потрібне передбачуване збереження state під час перемикань видимості (таби, drawer, navigation shell). <Activity/> робить намір явним; воно не зупиняє автоматично дорогі таймери/subscription-и в прихованому UI — це все ще твоє архітектурне рішення, де має жити “важка робота”. [2]
useEffectEvent: не перепідключайся лише через зміну теми
Effects мають відому напругу: ти хочеш правильні dependency array, але інколи хочеш, щоб handler бачив найсвіжіші значення без перезапуску effect.
У React 19.2 useEffectEvent формалізує цей патерн. У пості про React 19.2 є приклад чату: зміна theme не повинна перепідключати чат, але notification має використати найновішу тему. useEffectEvent виносить “event-like” логіку з effect. [2][6]
Практичний приклад (analytics/logging), який дружить із лінтером:
import { useEffect, useEffectEvent } from "react";
type Props = { userId: string; plan: "free" | "pro" };
declare function subscribeToBillingEvents(
userId: string,
onEvent: (name: string) => void,
): () => void;
declare function track(event: string, props: Record<string, string>): void;
export function BillingWatcher({ userId, plan }: Props) {
const onBillingEvent = useEffectEvent((name: string) => {
track("billing_event", { name, plan });
});
useEffect(() => {
return subscribeToBillingEvents(userId, (name) => onBillingEvent(name));
}, [userId]);
return null;
}Архітектурна підказка: useEffectEvent — великий win, якщо сьогодні ти вимикаєш hooks linter лише щоб не ререндерити/не перезапускати effect. Але не загортай у нього все: React прямо попереджає не використовувати його тільки для “заспокоєння” лінтера. Використовуй, коли логіка по суті є подією, а не частиною реактивного effect “синхронізуй систему”. [2][6]
Performance Tracks: scheduling React стає видимим (і реально debuggable)
Раніше performance debugging часто був гаданням: “чому цей update відчувається повільним?”. Performance Tracks робить роботу React прозорою в timeline.
Performance Tracks не робить застосунки швидшими “магічно”. Він робить роботу над продуктивністю чеснішою: менше вайбу, більше доказів. [5]
Чому це важливо
Замість “React повільний” ти бачиш, що React робив і коли — особливо навколо взаємодій і schedulinga. [5]
Де найбільше допомагає
Ідеально для повільних кліків, input lag, suspense reveal та довгих commit, бо робота підписана в timeline. [5]
Performance Tracks у дії: робота React з’являється як окремі треки в Performance timeline. [2][5]
Section performance-tracks screenshotOverview: timeline розділяє Scheduler, Components і ключові фази (blocking, transitions, suspense). [5]
Section performance-tracks screenshotScheduler track: видно таймінги подій і фази на кшталт update, render, commit та waiting for paint. [5]
Section performance-tracks screenshotClose-up: допомагає точно побачити, яка фаза домінує у повільній взаємодії. [5]
Section performance-tracks screenshotReact 19.2 SSR: batched Suspense reveal зменшує “прогресивний хаос”
React 19.2 змінює те, як відкриваються SSR Suspense boundary: boundary, які завершуються одночасно, можуть відкриватись батчем. Мета — наблизити SSR streaming до поведінки на клієнті і зменшити дивну фрагментацію reveal. [2]
Це хороший приклад напряму React у 2026: зробити reveal більш передбачуваним і менш залежним від випадковостей таймінгу. [2]
Ефект для користувача
Менше “одне з’явилось, потім друге, потім третє”, коли boundary завершуються одночасно. [2]
Ефект для розробника
SSR streaming стає ближчим до client-поведінки, що спрощує ментальні моделі й дебаг. [2]
Архітектурна підказка
Suspense boundaries — частина UX-дизайну. Групуй те, що має з’явитись разом, і розділяй те, що може прийти пізніше. [2]
React Compiler 1.0: memoization переходить з code review у build-time
React Compiler 1.0 — стабільний і production-ready. Це build-time інструмент, який оптимізує компоненти та хуки через автоматичну memoization і додає compiler-powered lint rules через пресети eslint-plugin-react-hooks. [3]
Ідея не в тому, що “React повільний без компіляції”. Ідея в тому, що ручна memoization часто error-prone, непослідовна між командами і перетворюється на cargo-cult useMemo/useCallback всюди.
Порада React прагматична: покладайся на compiler за замовчуванням, а useMemo/useCallback тримай як escape hatch, коли потрібен точний контроль (часто навколо залежностей effect). Також уважно тестуй перед видаленням існуючої memoization, бо це може змінити output компіляції. [3]
Мінімальний приклад, що змінюється архітектурно (менше ручної оптимізації):
type Props = { items: Array<{ id: string; price: number }>; taxRate: number };
declare function expensiveTotal(items: Props["items"], taxRate: number): number;
declare function CheckoutSummary(props: { total: number }): JSX.Element;
export function Cart({ items, taxRate }: Props) {
const total = expensiveTotal(items, taxRate);
return <CheckoutSummary total={total} />;
}З compiler-ом ти часто можеш залишити код декларативним і дозволити інструменту вирішити, що безпечно memoize — за умови, що ти дотримуєшся Rules of React і нормально тестуєш. [3]
Partial Pre-rendering: новий важіль для “статична оболонка + динамічне заповнення”
Partial Pre-rendering (React DOM, 19.2) — це ідея наперед пререндерити статичні частини (CDN-friendly), а потім “resume” пізніше, щоб підставити динаміку. У пості React 19.2 показано флоу prerender() → зберегти postponed state → resume(). [2]
Архітектурна підказка: для content-heavy сайтів, де оболонка переважно статична, а персоналізація/дані — динамічні, PPR може бути дуже корисним. Але trade-off операційний: це не “просто React”, це рендеринг-пайплайн і вибір інтеграції framework/bundler. [2]
React Server Components: стабільно, але сприймай екосистему як систему
React Server Components (RSC) стабільні на рівні React у React 19, але docs прямо попереджають: underlying API, які використовують bundler/framework, можуть ламатися між minor 19.x і не слідують semver. Для implementer-ів рекомендують pinning на конкретну версію React або використання Canary. [4]
Також: слідкуй за security advisory. Команда React публікувала RSC вразливості для react-server-dom-* і рекомендувала оновлення до виправлених версій. [7]
Архітектурна підказка: якщо ти використовуєш RSC, стався до React версії, інтеграції framework/bundler і пакетів react-server-dom-* як до однієї upgrade-одиниці — з дисципліною по патчах.
Роадмап серії: наступні deep-dive статті (з реальним кодом і патернами)
Цей пост — огляд. Далі йдемо вглиб — по одному концепту — з практичними прикладами і архітектурними trade-off.
• Actions у реальних застосунках: форми, optimistic UI, форматування помилок і інтеграція з React Query/SWR. [1][8]
• <Activity/> у практиці: tab shell, drawer, route-like патерни й як уникати leak у hidden subtree. [2]
• useEffectEvent патерни: analytics, subscription, real-time socket і design effect, дружній до лінтера. [2][6]
• Performance Tracks playbook: що дивитись, типові патерни і як читати фази в реальних застосунках. [5]
• SSR Suspense boundary design: імплікації batchinga і архітектури boundary для чистих reveal. [2]
• React Compiler adoption: інкрементальний rollout, стратегія тестів і коли залишати ручну memoization. [3]
• Partial Pre-rendering архітектура: що пререндерити, де resume і CDN/edge імплікації. [2]
• RSC hardening checklist: pinning, patch cadence і playbook реакції на advisory. [4][7]
Джерела
Ми включаємо лише джерела, які напряму підтверджують твердження та приклади з цієї статті.
• 1. React v19 (офіційно): Actions, useActionState, <form> Actions, useFormStatus, useOptimistic Читати джерело ↗
• 2. React 19.2 (офіційно): <Activity/>, useEffectEvent, Performance Tracks, SSR batching, Partial Pre-rendering Читати джерело ↗
• 3. React Compiler v1.0 (офіційно): стабільний реліз, автоматична memoization, lint rules, інкрементальна адаптація Читати джерело ↗
• 4. Server Components reference (офіційно): стабільність + попередження про bundler/framework API; pinning guidance Читати джерело ↗
• 5. React Performance Tracks (офіційно): що показують треки і як користуватись profiling/dev build Читати джерело ↗
• 6. Separating Events from Effects (офіційно): ментальна модель за useEffectEvent Читати джерело ↗
• 7. RSC security advisory (офіційно): DoS та source code exposure; рекомендації щодо upgrade Читати джерело ↗
• 8. useActionState reference (офіційно): визначення API та деталі використання Читати джерело ↗
Часті запитання
Якщо ти вже на React 19, 19.2 — практичне оновлення через нові примітиви й покращення devtools. Якщо використовуєш React Server Components, також слідкуй за security advisory від React Team і переконайся, що зачеплені пакети оновлені до виправлених версій. [2][7]
Ні. Actions зменшує UI-boilerplate для мутацій і форм. Data-бібліотеки все ще сильні для caching, retry, background refresh, offline-поведінки й cross-screen консистентності. У багатьох застосунках ти комбінуватимеш їх свідомо. [1][8]
Він допомагає тримати залежності effect коректними, не перепідключаючи/не перезапускаючи effect лише тому, що handler має бачити найновіші значення. Особливо корисно, якщо сьогодні ти вимикаєш hooks linter, щоб уникати re-run. [2][6]
Концептуально так, але важливе — зробити намір явним і дати React правильний примітив для “hidden but alive” UI. Ця ясність допомагає архітектурі й відкриває шлях до майбутніх покращень schedulinga/пріоритизації. [2]
Не автоматично. Рекомендація React: покладайся на compiler за замовчуванням, memo хуки тримай як escape hatch, коли потрібен точний контроль (часто навколо залежностей effect). І уважно тестуй перед видаленням існуючої memoization. [3]
RSC стабільні на рівні React у React 19, але інтеграція екосистеми (bundler/framework) — системне питання. Дотримуйся pinning guidance там, де це релевантно, і слідкуй за security advisory для `react-server-dom-*`. [4][7]
Хочеш upgrade без регресій?
Нові примітиви React потужні — але безпечна адаптація все одно вимагає інженерної гігієни: тести, лінт і чіткий архітектурний план.
Якщо плануєш React upgrade (або хочеш впровадити Compiler/Actions/RSC без поломок у проді), PAS7 Studio може допомогти audit-first підходом і rollout стратегією під твій стек.