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 р.· 7 хв читання· Технології
Превʼю React <Activity /> на фоні компʼютерного заліза: “State kept. Effects paused.”

В огляді ми пояснюємо, як 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

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

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 означає “React не рендерить”. Він може re-render — але з нижчим пріоритетом.

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

hidden

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

збережений

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

знищені

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

deprioritized

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

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

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

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

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]

Це “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 (нижче покажемо як правильно).

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-хак.

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.

Це найпопулярніша 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 перестало оновлюватись”.

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>
    </>
  );
}

hidden не входить

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

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

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

advanced panels

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

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

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

Якщо 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.

Швидка 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]

0

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

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

Ви тут03/04

React <Activity />: зберігайте state, ставте Effects на паузу і рендерьте у фоні

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

growth

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

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

blogs

Найпотужніший чіп від Apple? M5 Pro і M5 Max б'ють рекорди

Аналітичний розбір Apple M5 Pro і M5 Max станом на березень 2026 року. Пояснюємо, чому ці чіпи можна вважати найпотужнішими професійними ноутбучними SoC від Apple, як вони виглядають на тлі M4 Pro, M4 Max, M1 Pro, M1 Max і що показують у порівнянні з актуальними Intel та AMD.

blogs

Artemis II і код, який веде до Місяця

У цьому блозі розбираємо місію NASA Artemis II, яка стартувала 1 квітня 2026 року, і пояснюємо, що вона насправді говорить про сучасну інженерію: бортове ПЗ, резервні контури, симуляції, телеметрію, людський контроль і дуже обережну роль ШІ в космічній сфері.

telegram-media-saver

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

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

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

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