PAS7 Studio

Технології

React <Activity /> deep dive: зберігає state, ставить Effects на паузу, рендерить у фоні — практичні патерни, реальні edge cases і чекліст rollout

<Activity /> (React 19.2) — третій варіант між unmount UI та CSS-hide: він зберігає state, ховає DOM, знищує Effects і зсуває hidden-оновлення у нижчий пріоритет. Це продовження гайду про React 2026 primitives: тут — реальні патерни для tabs/drawers/shell UI, pre-render наступного екрану, SSR/hydration наслідки, пастки екосистеми та production чекліст.

24 лют. 2026 р.· 18 хв читання
Превʼю React <Activity /> на фоні компʼютерного заліза: “State kept. Effects paused.”
Гайд / СеріяСтаття серії

React 2026 Primitives & Compiler Upgrade Guide

Фокусний розділ про <Activity />. Спочатку прочитайте огляд, далі — впроваджуйте патерни інкрементально з вимірюваними guardrails.

Усі статті в цьому гайді

01

Overview: React 2026 primitives and compiler-era mental model

Загальна картина: що змінилось і де кожен примітив реально підходить.

Опубліковано

02

useActionState deep dive: mutation flows, optimistic UI, and integration patterns

Коли useActionState знімає boilerplate, а коли data layer все ще “власник” проблеми.

Заплановано

03

React <Activity />: keep state, pause Effects, background render

Практичні патерни, performance trade-offs, пастки екосистеми та чекліст rollout.

Ви тут

04

useEffectEvent deep dive: effect design, subscriptions, and analytics

Linter-friendly межі для ефектів без stale closures та reconnect churn.

Заплановано

Частина React 2026 гайду

В огляді ми пояснюємо, як Actions, <Activity />, useEffectEvent, Performance Tracks, SSR batching та Compiler складаються в один напрям (а не набір випадкових фіч).[2]

Це розділ з нашого гайду про React 2026 primitives. Якщо хочете спочатку дорожню карту — почніть з огляду:

Що ви заберете з цього розділу

Docs прямо кажуть: у hidden React ховає дітей через display: none, знищує Effects (cleanup підписок), зберігає state, і діти можуть re-render на нові props (нижчий пріоритет).[1]

<Activity /> найкраще розуміти як lifecycle + scheduling контроль для hidden UI. Цей розділ — про те, як використати його і не зробити гірше.

  • Реальна семантика mode="visible" | "hidden": DOM, state, Effects, пріоритет апдейтів.[1][2]

  • Патерни, які реально працюють: tabs/drawers, “warm next screen”, важкі панелі, SSR gating.[1][2]

  • Як зробити hidden-роботу дешевою (контроль prop churn) і не створити випадково дорогі оновлення.[1]

  • Edge cases екосистеми: що ламається в third-party віджетах і як себе захистити.[7]

  • Production чекліст rollout (feature flags + метрики + memory budget).

React 19.2: hidden ховає дітей, unmount Effects, дефери апдейти і дозволяє background preparation.[2]

Скріншот секції overview

Навіщо <Activity />: прогалина між unmount та CSS-hide

Історично більшість апок використовували:

1) Conditional rendering: життєвий цикл чистий, але ви втрачаєте локальний state при unmount (форми, scroll, еферемний UI-state).

2) CSS hide: state зберігається, але hidden піддерева можуть тримати підписки/таймери і конкурувати за main-thread.

React 19.2 позиціонує Activity як спосіб розбити апку на “activities”, які можна контролювати і пріоритизувати. У hidden він ховає дітей, unmount Effects і дефери апдейти, доки React не залишиться нічого важливішого.[2]

Ментальна модель: що робить `hidden` (і чого не робить)

Найчастіша помилка: думати, що hidden означає “React не рендерить”. Він може re-render — але з нижчим пріоритетом.

React Labs пояснює задум: концептуально компонент “unmounted”, але React зберігає state. Вони радять <StrictMode>, щоб рано знаходити проблемні Effects — Activity буде mount/unmount Effects при перемиканні.[3]

DOM

hidden

React ховає дітей через display: none у hidden.[1]

State

збережений

React зберігає state, щоб UI швидко відновився у visible.[1]

Effects

знищені

Effects cleanup у hidden; при visible — монтуються знову.[1][2]

Updates

deprioritized

Hidden діти можуть re-render на props з нижчим пріоритетом.[1]

React Reference: hidden ховає DOM, знищує Effects, дефери апдейти; visible відновлює попередній state і пересоздає Effects.[1]

Скріншот секції mental-model

API: базовий патерн

Мінімальне використання:

TSX
import { Activity, useState } from "react";

export function SidebarShell() {
  const [open, setOpen] = useState(false);

  return (
    <>
      <button onClick={() => setOpen((v) => !v)}>
        {open ? "Hide" : "Show"}
      </button>

      <Activity mode={open ? "visible" : "hidden"}>
        <Sidebar />
      </Activity>
    </>
  );
}

З reference: у hidden Effects знищуються (cleanup), діти ховаються через display: none, і можуть re-render на props з нижчим пріоритетом.[1]

Патерн 1: Tabs / drawers з state без hidden side-effects

Це “killer” кейс: зберегти state (форми, scroll), але не тримати підписки/таймери активними у hidden.[1][2]

TSX
import { Activity } from "react";

export function SettingsTabs({ tab }: { tab: "profile" | "billing" }) {
  return (
    <>
      <Activity mode={tab === "profile" ? "visible" : "hidden"}>
        <ProfileTab />
      </Activity>
      <Activity mode={tab === "billing" ? "visible" : "hidden"}>
        <BillingTab />
      </Activity>
    </>
  );
}

Якщо вкладка потребує безперервної background-роботи для коректності — не ховайте “двигун” всередині Activity (нижче покажемо як правильно).

Патерн 2: “Warm next screen” по intent (hover/focus) без блокування форграунду

React 19.2 прямо каже: можна pre-render і продовжувати рендерити hidden частини без впливу на visible performance.[2] Трюк — почати прогрів на *intent* (hover/focus), а не на клік.

TSX
import { Activity, useEffect, useState } from "react";
import { useRouter } from "next/navigation";

export function ContinueButton({ nextHref }: { nextHref: string }) {
  const router = useRouter();
  const [armed, setArmed] = useState(false);

  useEffect(() => {
    if (!armed) return;
    router.prefetch(nextHref);
  }, [armed, nextHref, router]);

  return (
    <>
      <button onMouseEnter={() => setArmed(true)} onFocus={() => setArmed(true)}>
        Continue
      </button>

      <Activity mode={"hidden"}>
        <NextStepShell />
      </Activity>
    </>
  );
}

Цей варіант свідомо консервативний: він готує піддерево у фоні, але ніколи його не показує до навігації. Це scheduling hint, не UI-хак.

Патерн 3: Здешевіть hidden рендер — контролюйте prop churn на межі

TSX
import { Activity, useMemo } from "react";

type Filters = { key: string; q: string; sort: "new" | "top" };

export function HeavyPanelHost(props: {
  visible: boolean;
  filters: Filters;
  liveTick: number;
}) {
  const stableFilters = useMemo(() => props.filters, [props.filters.key]);

  return (
    <Activity mode={props.visible ? "visible" : "hidden"}>
      <HeavyPanel filters={stableFilters} />
    </Activity>
  );
}

Hidden діти можуть re-render на зміни props.[1] У реальних апках основна ціна — це не Activity, а постійно змінні props, які ви прокидуєте в hidden дерево.

  • Не передавайте high-frequency значення (now, стрімові метрики, scroll position) у hidden дерева.

  • Стабілізуйте props, які не мають змінюватись у hidden (memoize по stable key).

  • Якщо live значення потрібні — тримайте їх у маленькому stable engine і передавайте в hidden тільки грубий snapshot.

Патерн 4: Не ховайте data engine всередині Activity

Це найпопулярніша production пастка: Activity знищує Effects у hidden.[1][2] Якщо коректність залежить від постійних підписок/полінгу — винесіть двигун назовні й передавайте дані всередину.

TSX
import { Activity, useEffect, useState } from "react";

type Live = { count: number };

declare function subscribeLive(onValue: (v: Live) => void): () => void;

function LiveEngine({ onValue }: { onValue: (v: Live) => void }) {
  useEffect(() => subscribeLive(onValue), [onValue]);
  return null;
}

export function ScreenWithPanel({ open }: { open: boolean }) {
  const [live, setLive] = useState<Live>({ count: 0 });

  return (
    <>
      <LiveEngine onValue={setLive} />
      <Activity mode={open ? "visible" : "hidden"}>
        <Panel live={live} />
      </Activity>
    </>
  );
}

Цей дизайн робить коректність незалежною від видимості панелі й прибирає баги типу “в hidden перестало оновлюватись”.

SSR / hydration наслідки (тут Activity стає архітектурним інструментом)

Activity — це не лише про state retention. Це також SSR-важіль: що входить у початковий HTML, а що ви свідомо відкладете.

Практичний SSR gating приклад:

TSX
import { Activity, useState } from "react";

export function Page() {
  const [advanced, setAdvanced] = useState(false);

  return (
    <>
      <PrimaryContent />
      <button onClick={() => setAdvanced((v) => !v)}>Advanced</button>

      <Activity mode={advanced ? "visible" : "hidden"}>
        <AdvancedPanel />
      </Activity>
    </>
  );
}

SSR response

hidden не входить

Reference каже: UI всередині mode="hidden" не включається в SSR response.[1]

Hydration

важливий пріоритет

Reference описує наслідки scheduling/hydration навколо visibility та пріоритизації.[1]

Use case

advanced panels

Тримайте truly non-critical UI поза initial HTML, щоб зменшити payload і покращити perceived load.

ViewTransition: show/hide Activity може тригерити анімації

Reference має caveat: коли Activity всередині ViewTransition, show/hide може активувати enter/exit анімації залежно від того, як виконано апдейт.[1]

Якщо ви будуєте navigation shell з transitions — тестуйте Activity toggles окремо під startTransition і вашим патерном ViewTransition (таймінг і межі анімації мають значення).

Реальні edge cases екосистеми: що ламається і як захищатись

Якщо third-party компонент тримає інтерактивний state всередині, але реініціалізується при mount, Activity toggles це проявлять. Тоді зазвичай потрібне: (a) винести state назовні (controlled props), (b) оновити/патчити бібліотеку, або (c) не обгортати цей сабтрі Activity.

Найшвидший спосіб втратити довіру до нового примітиву — загнати його в third-party компонент, який не розрахований на такі lifecycle-семантики.

  • deck.gl: issue, де приховування <DeckGL> через Activity скидає view state після повторного показу.[7]

  • Prior art keep-alive допомагає думати про eviction, cache budgets і “що саме варто зберігати”.[8]

  • Безпечний rollout: стартуйте з owned UI (таби/дровери/форми), а потім — third-party heavy widgets тільки після тестів на відновлення state.

Production rollout чекліст (як ми це робимо на клієнтських проєктах)

Швидка KPI табличка для PR опису:

MD
| Metric | Baseline | After Activity | Notes |
|---|---:|---:|---|
| INP (p75) |  |  | toggle tabs/drawer |
| Long tasks > 50ms |  |  | navigation + warmup |
| JS heap after 5 toggles |  |  | memory budget check |
| CPU time during toggle |  |  | prop churn detection |

Activity має сенс, якщо він покращує UX без прихованих регресій по памʼяті/CPU. Сприймайте як rollout, а не як “рефактор”.

  • Feature flag на нову межу + поступовий rollout (per route / per segment).

  • Міряйте: INP, long tasks, memory growth (особливо якщо багато hidden activities).

  • У dev/staging увімкніть <StrictMode>, щоб зловити неправильні припущення про Effects.[3]

  • Задайте memory budget: скільки hidden “screens” дозволяєте одночасно.

  • Тестуйте Activity toggles з: Suspense boundaries, navigation transitions і third-party віджетами.

Часті запитання

Чи означає `hidden`, що React взагалі не рендерить піддерево?

Ні. Reference прямо каже, що діти можуть re-render у відповідь на нові props, але з нижчим пріоритетом за visible контент.[1]

Чи будуть працювати підписки/таймери, поки Activity hidden?

Ні. Коли Activity стає hidden, React знищує Effects (виконує cleanup) і монтує їх знову, коли Activity стає visible.[1][2]

Чи замінює Activity віртуалізацію списків (react-window, virtuoso)?

Ні. Віртуалізація зменшує DOM/рендер для великих списків. Activity — про lifecycle/scheduling для цілих UI-піддерев: табів, дроверів, екранів.[1][2]

Чи може Activity допомогти з SSR перформансом?

Так, як свідомий важіль: reference каже, що UI всередині `mode="hidden"` не включається в SSR response, що може зменшити initial HTML для non-critical панелей.[1]

Яка найбільша production пастка з Activity?

Сховати піддерево, яке містить “data engine” через Effects (підписки/полінг). Hidden знищує Effects, тож коректність ламається, якщо двигун не винести назовні межі Activity.[1][2]

Чи достатньо стабільний Activity для production?

Він відвантажений у React 19.2 і має документовану поведінку та офіційний reference.[1][2] React Labs радить StrictMode під час adoption, щоб зловити неочікувані side effects, коли Effects монтуються/демонтуються через Activity toggles.[3]

Джерела

Хочете впровадити Activity без регресій?

PAS7 Studio допомагає безпечно впроваджувати React 19.2 primitives: Activity, Suspense, transitions і Next.js prefetch патерни — з вимірюваними метриками до/після.

Отримаєте конкретний rollout план: де Activity допомагає, де шкодить, і як тримати памʼять + CPU під контролем.

Ви тут03/04

React <Activity />: keep state, pause Effects, background render

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

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

growth15 лютого 2026 р.

AI SEO / GEO у 2026: ваші наступні клієнти — не люди, а агенти

Пошук зміщується від кліків до відповідей. Боти та AI-агенти сканують, цитують, рекомендують і дедалі частіше купують. Дізнайтесь, що таке AI SEO / GEO, чому класичного SEO вже недостатньо, і як PAS7 Studio допомагає брендам перемагати у «агентному» вебі.

Читати →
telegram-media-saver8 січня 2025 р.

Автоматичне тегування та пошук збережених посилань

Інтеграція з GDrive/S3/Notion для автоматичного тегування та швидкого пошуку через пошукові API

Читати →
services1 січня 2025 р.

Розробка Telegram-ботів та автоматизація

Професійна розробка Telegram-ботів та автоматизація бізнес-процесів: чат-боти, AI-асистенти, інтеграції з CRM та автоматизація процесів.

Читати →
backend-engineering15 лютого 2026 р.

Bun vs Node.js у 2026: чому Bun відчувається швидшим (і як перевірити застосунок перед міграцією)

Bun — це швидший all-in-one JavaScript toolkit: runtime, пакетний менеджер, бандлер і тест-раннер. Розбираємо, що реально дає приріст (з бенчмарками), що може зламатися, і як отримати безкоштовний readiness-аудит через @pas7-studio/bun-ready.

Читати →

Професійна розробка для вашого бізнесу

Створюємо сучасні веб-рішення та боти для бізнесу. Дізнайтеся, як ми можемо допомогти вам досягти цілей.