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.
Recent Posts
-
Aug 22 2026
-
Aug 22 2026
-
Aug 22 2026