Tecnologia
React <Activity /> deep dive: stato preservato, Effects in pausa, render in background — pattern pratici, edge case reali e checklist di rollout
<Activity /> (React 19.2) è la terza via tra smontare UI e nasconderla via CSS: preserva lo state, nasconde il DOM, distrugge gli Effects e de-prioritizza gli aggiornamenti hidden. Questo capitolo (parte della guida React 2026 Primitives) copre pattern reali per tabs/drawers/shell UI, pre-render del prossimo screen, implicazioni SSR/hydration, insidie dell’ecosistema e una checklist di rollout in produzione.

React 2026 Primitives & Compiler Upgrade Guide
Capitolo focalizzato su <Activity />. Leggi prima l’overview, poi adotta i pattern in modo incrementale con guardrail misurabili.
Tutti gli articoli di questa guida
01
Overview: React 2026 primitives and compiler-era mental model
Visione d’insieme: cosa è cambiato e dove si colloca ogni primitivo.
02
useActionState deep dive: mutation flows, optimistic UI, and integration patterns
Quando useActionState riduce il boilerplate e quando un data layer resta il vero owner.
03
React <Activity />: keep state, pause Effects, background render
Pattern pratici, trade-off di performance, insidie dell’ecosistema e checklist di rollout.
04
useEffectEvent deep dive: effect design, subscriptions, and analytics
Confini degli effect compatibili con il linter senza stale closures o reconnect churn.
Parte della guida React 2026
Nell’overview spieghiamo come Actions, <Activity />, useEffectEvent, Performance Tracks, SSR batching e Compiler si incastrano come direzione (non feature casuali).[2]
Questo è un capitolo della nostra guida React 2026 Primitives. Se vuoi prima la roadmap, parti dall’overview:
Cosa ti porti via da questo capitolo
I docs sono espliciti: in hidden React nasconde i figli con display: none, distrugge gli Effects (cleanup delle subscription), preserva lo state e i figli possono re-renderizzare su nuovi props (priorità più bassa).[1]
<Activity /> è soprattutto controllo di lifecycle + scheduling per UI hidden. Qui parliamo di usarlo bene, senza peggiorare l’app.
• La semantica reale di
mode="visible" | "hidden": DOM, state, Effects, priorità degli update.[1][2]• Pattern che funzionano davvero: tabs/drawers, “warm next screen”, pannelli pesanti, SSR gating.[1][2]
• Come rendere economico il lavoro hidden (controllo del prop churn) ed evitare update costosi.[1]
• Edge case dell’ecosistema: cosa si rompe in widget third-party e come difendersi.[7]
• Checklist di rollout in produzione (feature flag + metriche + memory budget).
React 19.2: hidden nasconde i figli, unmount degli Effects, defer degli update e background preparation.[2]
Perché <Activity />: il gap tra unmount e CSS-hide
Storicamente la maggior parte delle app usava:
1) Conditional rendering: lifecycle pulito, ma perdi lo state locale quando la UI hidden fa unmount (form, scroll, UI state).
2) CSS hide: lo state resta, ma i subtree hidden possono tenere attive subscription/timer e competere sul main-thread.
React 19.2 presenta Activity come modo per dividere l’app in “activities” controllabili e prioritizzabili. In hidden, nasconde i figli, unmount degli Effects e defer degli update finché React non ha nulla di più importante.[2]
Mental model: cosa fa `hidden` (e cosa non fa)
Errore comune: pensare che hidden significhi “React non renderizza”. Può comunque re-renderizzare, ma a priorità più bassa.
React Labs chiarisce l’intento: concettualmente “unmounted”, ma React salva lo state. Consigliano <StrictMode> per trovare presto Effects problematici, perché Activity fa mount/unmount degli Effects quando toggli.[3]
React Reference: hidden nasconde DOM e distrugge Effects; visible ripristina lo state precedente e ricrea gli Effects.[1]
Screenshot della sezione mental-modelAPI: pattern base
Uso minimale:
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>
</>
);
}Dalla reference: in hidden gli Effects vengono distrutti (cleanup), i figli nascosti via display: none e possono re-renderizzare su props a priorità più bassa.[1]
Pattern 1: Tabs / drawers che preservano state senza side-effects hidden
Use case “killer”: preservare state (input form, scroll) ma non tenere subscription/timer attivi in hidden.[1][2]
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>
</>
);
}Se un tab richiede lavoro continuo per restare corretto, non nascondere l’engine dentro la boundary Activity (vedi Pattern 4).
Pattern 2: “Warm next screen” su intent (hover/focus) senza bloccare il foreground
React 19.2 dice esplicitamente che puoi pre-renderizzare e continuare a renderizzare parti hidden senza impattare la performance visibile.[2] Il trucco: avviare il warmup su *intent* (hover/focus).
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>
</>
);
}Questo pattern è volutamente conservativo: prepara il subtree in background ma non lo mostra fino alla navigazione. È un hint di scheduling, non un trucco UI.
Pattern 3: Rendere economico il render hidden controllando il prop churn alla boundary
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>
);
}I figli hidden possono re-renderizzare su cambi di props.[1] Nelle app reali, il costo principale è il flusso di props che cambiano continuamente verso subtree hidden.
• Evita di passare valori high-frequency (
now, streaming stats, scroll position) a subtree hidden.• Stabilizza i props che non devono cambiare in hidden (memoize per stable key).
• Se servono valori live: mantienili in una piccola engine stabile e passa snapshot al subtree hidden.
Pattern 4: Non nascondere il tuo data engine dentro Activity
Footgun più comune: Activity distrugge gli Effects in hidden.[1][2] Se la correttezza dipende da subscription/polling continui, sposta l’engine fuori e passa i dati dentro.
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>
</>
);
}Così la correttezza resta indipendente dalla visibility del pannello e riduci bug tipo “in hidden smette di aggiornare”.
SSR / hydration (qui Activity diventa uno strumento architetturale)
Activity non è solo state retention. È anche una leva SSR: cosa finisce nell’HTML iniziale e cosa decidi di deferire.
Esempio pratico di SSR gating:
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
La reference nota che UI dentro mode="hidden" non è inclusa nella SSR response.[1]
Hydration
La reference discute implicazioni di scheduling/hydration legate a visibility e prioritizzazione.[1]
Use case
Tieni UI davvero non-critica fuori dall’HTML iniziale per ridurre payload e migliorare perceived load.
ViewTransition: show/hide Activity può attivare animazioni
La reference di Activity include un caveat: se Activity è dentro ViewTransition, lo show/hide può attivare animazioni enter/exit a seconda di come avviene l’update.[1]
Se stai costruendo una navigation shell con transitions, testa i toggle di Activity sotto startTransition e con il tuo pattern ViewTransition (timing e confini contano).
Edge case reali nell’ecosistema: cosa si rompe e come difendersi
Se un componente third-party mantiene state interattivo internamente ma re-inizializza al mount, i toggle Activity lo renderanno evidente. In quel caso serve: (a) esternalizzare lo state (controlled props), (b) patch/upgrade della libreria, o (c) evitare Activity su quel subtree.
Il modo più rapido per perdere fiducia in un nuovo primitivo è usarlo attorno a componenti third-party non pensati per questa semantica di lifecycle.
• deck.gl: issue report — Activity hide/show può resettare view state dopo il re-show.[7]
• Il prior art “keep-alive” aiuta a ragionare su eviction, cache budgets e cosa preservare.[8]
• Rollout sicuro: inizia con owned UI (tabs/drawers/forms), poi estendi a widget third-party solo dopo test di state restoration.
Checklist di rollout in produzione (come lo facciamo nei progetti client)
Tabella KPI rapida da incollare nella descrizione PR:
| 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 vale la pena se migliora UX senza regressioni nascoste di memory/CPU. Trattalo come un rollout, non come un refactor.
• Feature flag per la nuova boundary + rollout graduale (per route / segment).
• Misura: INP, long tasks, crescita memoria (specie con molte hidden activities).
• Abilita
<StrictMode>in dev/staging per scovare assunzioni sbagliate sugli Effects.[3]• Definisci un memory budget: quante “screens” hidden permetti contemporaneamente.
• Testa i toggle Activity con: Suspense boundaries, navigation transitions e widget third-party pesanti.
FAQ
No. La reference di Activity dice esplicitamente che i figli possono re-renderizzare in risposta a nuovi props, ma con priorità più bassa rispetto al contenuto visibile.[1]
No. Quando Activity diventa hidden, React distrugge gli Effects (cleanup) e li rimonta quando torna visible.[1][2]
No. La virtualizzazione riduce DOM/render per liste grandi. Activity è lifecycle/scheduling per interi subtree UI come tabs, drawers e screens.[1][2]
Sì, come leva intenzionale: la reference nota che UI dentro `mode="hidden"` non è inclusa nella SSR response, riducendo l’HTML iniziale per pannelli non critici.[1]
Nascondere un subtree che contiene un “data engine” via Effects (subscription/polling). Hidden distrugge gli Effects, quindi la correttezza può rompersi se l’engine non viene spostato fuori dalla boundary Activity.[1][2]
È shipped in React 19.2 con comportamento documentato e reference ufficiale.[1][2] React Labs consiglia StrictMode durante l’adozione per trovare side effect inattesi quando gli Effects vengono mount/unmount tramite i toggle Activity.[3]
Fonti
• React Reference: <Activity> (DOM hiding, Effects cleanup, low-priority re-renders, SSR notes) Leggi fonte ↗
• React 19.2 (official): Activity semantics and goals Leggi fonte ↗
• React Labs: View Transitions, Activity, and more (StrictMode guidance; concept: unmounted but state preserved) Leggi fonte ↗
• React Learn: Preserving and Resetting State (baseline mental model for conditional rendering) Leggi fonte ↗
• LogRocket: React 19.2 is here (Activity + useEffectEvent overview and practical framing) Leggi fonte ↗
• This Week In React #252 (context roundup: React 19.2, Activity, useEffectEvent) Leggi fonte ↗
• deck.gl issue: Activity compatibility bug (state resets after hide/show) Leggi fonte ↗
• Prior art: React keep-alive patterns (state preservation, caching, eviction strategies) Leggi fonte ↗
Vuoi adottare Activity senza regressioni?
PAS7 Studio aiuta i team ad adottare in sicurezza i primitives di React 19.2: Activity, Suspense, transitions e pattern di prefetch Next.js — con metriche prima/dopo misurabili.
Riceverai un piano di rollout concreto: dove Activity aiuta, dove fa male, e come tenere memory + CPU sotto controllo.
React <Activity />: keep state, pause Effects, background render