Introduction to <Activity />

<Activity /> is presented in the source as a built-in React component introduced in React 19.2. Its purpose is to hide and show a part of the user interface while preserving the internal state of that subtree.

The important idea is simple: hiding a screen does not have to mean destroying its state. Activity lets React represent a subtree as either visible or hidden, so a frequently revisited screen can return with its previous UI state.

Basic syntax

import { Activity } from "react";

<Activity mode="visible">
  <Dashboard />
</Activity>

The two modes

visible — the subtree is displayed and works normally.

hidden — the subtree is hidden; React cleans up its Effects while preserving state for later restoration.

This makes Activity useful when the user repeatedly moves between screens and should not lose unfinished work.

Why it matters

Preserves state inside a UI subtree for restoration.

Supports tabs, dashboards, sidebars, and multi-step screens.

Can help frequently visited content return without rebuilding the user's unfinished UI state.

Memory trick: Activity = hide the UI now, restore it later with its state.

How Activity Works

Visible versus hidden

When an Activity is visible, React displays the subtree normally. When it becomes hidden, the subtree is not shown as normal visible UI and its Effects are cleaned up. The component state remains available so the subtree can be restored when it becomes visible again.

Activity lifecycle

The source describes the lifecycle as a simple cycle:

VISIBLE  →  HIDDEN  →  VISIBLE

 

State

What happens

Visible

UI is shown; Effects are active.

Hidden

UI is hidden; Effects are cleaned up; state is preserved.

Visible again

UI is restored; preserved state can return; Effects are recreated.

What is preserved?

The React subtree's internal state is preserved for restoration.

The hidden subtree is not displayed as normal visible UI.

Effects are cleaned up while the Activity is hidden.

When the subtree becomes visible again, its state can be restored and Effects are recreated.

When Activity is useful

Tabs where users switch back and forth.

Dashboards with several screens.

Navigation areas that users revisit.

Multi-step forms where entered values should remain available.

UI panels that should disappear temporarily without losing their unfinished state.

Activity is not a universal replacement

If a component is truly temporary and its state does not need to survive, ordinary conditional rendering can be clearer. Activity is most useful when restoring the subtree gives a real user-experience benefit.

Real-World Use Cases

1. Student Management System

The supplied document uses a Student Management System to explain the problem. A user enters information on a Students screen, opens Reports, and then returns to Students. With ordinary conditional rendering, the Students component may unmount and its local state may be lost.

Solution

Keep the Students subtree inside Activity. Show it when the Students tab is active and hide it when Reports is active.

const [activeTab, setActiveTab] = useState("students");

<Activity mode={activeTab === "students" ? "visible" : "hidden"}>
  <Students />
</Activity>

<Activity mode={activeTab === "reports" ? "visible" : "hidden"}>
  <Reports />
</Activity>

2. Multi-step registration form

The source also describes a three-step form: Personal Details → Education → Confirmation. If Step 1 is unmounted while the user is on Step 2, typed values can be lost.

<Activity mode={step === 1 ? "visible" : "hidden"}>
  <PersonalDetails />
</Activity>

<Activity mode={step === 2 ? "visible" : "hidden"}>
  <Education />
</Activity>

Putting each revisited step inside Activity makes hidden/visible switching explicit and supports restoration of the UI state.

When to choose it

The user frequently returns to the screen.

Losing unfinished input would be frustrating.

The screen has meaningful local state that should survive navigation.

The UI is part of a tab, dashboard, or multi-step workflow.

When simple conditional rendering is enough

If the screen is temporary and there is no reason to preserve its state, the simpler approach may be easier to understand and maintain.

 

Lifecycle and Software-Design Thinking

Activity lifecycle in practice

Activity is more than a visibility switch. Its value comes from separating UI visibility from state preservation. The source emphasizes that hidden Activity cleans up Effects while keeping the subtree's state available for restoration.

Why state preservation matters

Frequently visited screens can return to their previous UI state.

Multi-step forms can retain previously entered values.

Users can switch tabs without losing unfinished work.

External resources still require correct cleanup.

UML sequence thinking

The source includes a sequence model for tab switching. The flow can be read as: the user selects another screen → the tab manager changes Activity mode → the Activity hides or restores the dashboard subtree → React manages the related Effect lifecycle.

UML class thinking

The document also uses a conceptual class model to ask responsibility questions. React components are not literally Java classes here; the diagram is a design model for understanding who owns state, who starts synchronization, and who controls visibility.

Conceptual responsibility

React example

ChatRoom

Owns room-related UI and connection lifecycle.

Connection

Represents external synchronization.

EffectEvent

Represents event callback logic.

Activity

Controls visible/hidden subtree mode.

Dashboard

Owns screen-specific state and UI.

TabManager

Chooses the active screen.

Think in responsibilities

Instead of asking only “What code should I write?”, ask: Which component owns this state? Who starts this connection? Who decides when this screen is visible? This way of thinking makes React architecture easier to explain in code reviews and interviews.

 

useEffect, useEffectEvent and Activity

The source treats these APIs as solving different lifecycle problems. Choosing the right one starts with identifying the actual problem rather than trying to make an Effect run less often.

Topic

useEffect

useEffectEvent

<Activity />

Primary purpose

Synchronize with an external system

Separate Effect-driven event logic

Hide/restore a UI subtree

Typical trigger

Dependency changes / lifecycle

Event from an Effect-managed system

Mode changes

State preservation

Depends on component lifecycle

Not its purpose

Designed to preserve subtree state

Common examples

Connection, timer, subscription

Notification, callback, listener logic

Tabs, dashboards, multi-step screens

Cleanup

Effect cleanup

Uses surrounding Effect cleanup

Hidden Activity cleans up Effects

Quick selection

Requirement

Choose

Connect to an external system

useEffect

React to an event using the latest values

useEffectEvent

Hide a screen and restore it later

<Activity />

Handle a simple button click

Normal event handler

Perform a pure calculation from props/state

Usually no Effect

The key distinction

useEffect manages synchronization. useEffectEvent is for event logic used by an Effect-managed system when that logic needs current props or state without making those values control synchronization. Activity manages UI visibility and state restoration.

A common mistake

The source warns against using useEffectEvent simply to remove dependencies. If a value genuinely determines the external synchronization, it should remain in the dependency array.

 

Student Management System Architecture

Putting the concepts together

The supplied document connects the theory to a realistic Student Management System. A parent can manage the active page while Activity keeps frequently visited screens restorable.

const [page, setPage] = useState("dashboard");

<Activity mode={page === "dashboard" ? "visible" : "hidden"}>
  <Dashboard />
</Activity>

<Activity mode={page === "students" ? "visible" : "hidden"}>
  <Students />
</Activity>

<Activity mode={page === "reports" ? "visible" : "hidden"}>
  <Reports />
</Activity>

Where useEffectEvent can fit

The source places useEffectEvent inside an Effect-managed notification connection. The connection is responsible for synchronization; the event callback reads the latest notification settings.

const onStudentNotification = useEffectEvent(() => {
  showNotification("New student added", notificationTheme);
});

useEffect(() => {
  const connection = createStudentNotificationConnection();
  connection.on("student-added", onStudentNotification);
  return () => connection.disconnect();
}, []);

Expected benefits

Tabs can restore local screen state when revisited.

Long-lived external connections stay tied to their real synchronization conditions.

Event callbacks can read the latest UI settings.

Responsibilities become easier to explain in architecture discussions.

How the APIs work together

Activity decides whether a screen should be visible. useEffect decides whether an external system should be synchronized. useEffectEvent handles event logic produced by that synchronized system. Keeping these responsibilities separate makes the design easier to reason about.

Step-by-step reasoning

1. Decide whether the screen should be visible. That is an Activity concern.

2. Decide whether the screen needs an external connection. That is an Effect concern.

3. Decide what should happen when the connection fires an event. That can be an Effect Event concern.

4. Make sure every external resource has correct cleanup.

 

Advanced Combined Example and Decision Rules

Chat + Activity

The source gives a larger example where a chat screen is hidden with Activity while useEffect manages the chat connection. When a message arrives, useEffectEvent can handle the event using the latest theme.

function AdminChat({ roomId, theme }) {
  const onMessage = useEffectEvent((message) => {
    showNotification(message, theme);
  });

  useEffect(() => {
    const connection = createConnection(roomId);
    connection.on("message", (message) => onMessage(message));
    connection.connect();
    return () => connection.disconnect();
  }, [roomId]);

  return <ChatPanel />;
}

<Activity mode={showChat ? "visible" : "hidden"}>
  <AdminChat roomId={roomId} theme={theme} />
</Activity>

Responsibility of each feature

useEffect → manages the external chat connection.

useEffectEvent → handles event logic that needs the latest values without making those values control synchronization.

<Activity /> → controls whether the chat UI is visible or hidden while preserving its state.

Beginner decision guide

Start with one question: “What problem am I trying to solve?”

Problem

First choice

External system must be synchronized

useEffect

Effect-driven event needs latest props/state

useEffectEvent

UI should be hidden and restored with state

<Activity />

User directly clicks a button

Event handler

Simple value can be calculated from props/state

Calculate during render

If there is no external system

Not every piece of code belongs inside useEffect. A simple calculation such as total = price * quantity normally belongs during rendering. A button click normally belongs in an event handler. The source's central rule is to use Effects for synchronization with something outside React.

If a dependency causes a reconnect

Do not remove it automatically. Ask whether the value actually changes the external synchronization. If roomId changes the connection, it should remain a dependency. If a value is only needed when an event occurs, useEffectEvent may be appropriate.

Best Practices, Conclusion and Revision

Best practices

1. Use useEffect for synchronization with external systems.

2. Do not use useEffect for ordinary calculations that can be performed during rendering.

3. Use useEffectEvent only for event logic that genuinely needs the latest values without controlling synchronization.

4. Keep real synchronization dependencies explicit.

5. Use <Activity /> when hiding and restoring a UI subtree gives a real UX benefit.

6. Always clean up timers, listeners, subscriptions, and connections.

7. Do not use useEffectEvent just to avoid dependency warnings.

8. Prefer simple React code when a simpler solution is enough.

Final rule for choosing the API

If the problem is...

Use...

External synchronization

useEffect

Effect event logic needing latest values

useEffectEvent

Hiding UI while preserving state

<Activity />

Three-line revision

useEffect → synchronize with an external system.

useEffectEvent → read the latest values inside Effect-driven event logic.

<Activity /> → hide UI while preserving its state and restore it later.

Final conclusion

The most important lesson from the supplied document is not memorizing syntax. It is learning to identify the real lifecycle problem. If the problem is synchronization, think useEffect. If an Effect-managed event needs current values without controlling synchronization, think useEffectEvent. If the problem is hiding a UI subtree while preserving its state, think Activity.

A professional React developer asks what should cause an external system to synchronize again, which state must survive navigation, and which component owns each responsibility. These questions lead to clearer dependencies, cleaner lifecycle behavior, and easier-to-maintain React applications.

FAQ

What is <Activity />?

It is a React component for hiding and showing a UI subtree while preserving its internal state so the subtree can be restored later.

Should I use <Activity /> instead of conditional rendering everywhere?

No. <Activity /> is most useful when a UI subtree is frequently revisited and preserving its state provides a real user-experience benefit. For simple temporary UI, normal conditional rendering may be clearer.

What happens when <Activity /> mode is hidden?

The subtree is hidden from the normal visible UI. Its Effects are cleaned up while the subtree remains available so that it can be restored when the mode becomes visible.

Does <Activity /> preserve component state?

Yes. The main purpose of <Activity /> is to preserve the subtree’s state so that when it becomes visible again, the user can continue from the previous state.

When should I use <Activity />?

Use it for UI such as tabs, dashboards, navigation pages, and multi-step forms where users frequently switch screens and expect their previous state to remain.

Is <Activity /> useful for a multi-step form?

Yes. For example, when a user moves from Personal Details Education Confirmation, Activity can keep the previous step's state available when the user returns to it.

What is the main difference between <Activity /> and normal conditional rendering?

Normal conditional rendering can remove a component subtree when its condition becomes false. <Activity /> is designed to hide the subtree while preserving it for later restoration.