# Introduction
The way React docs describes `<Activity />` as a Component that let's you hide and restore the UI and internal state of it's children.
Let's Understand what it means.
The Activity component has two modes `visible` and `hidden`.
1. When the mode is `visible`, it creates the Effects and renders the children.
2. When the mode is `hidden`, it visually hides the children using `display: none` and also destroys all the Effects
3. Even when the component is `hidden` the Children still re-render based on props
4. If a component starts with `hidden` mode, it will not create any Effects until it becomes `visible`, but the component is in the Browser DOM with `display: none`. Which means the component is rendered without calling any effects
Let's see an Example
```tsx
import { Activity, useEffect, useLayoutEffect, useState } from 'react';
import { Button } from '@/components/ui/button';
const ComponentInsideActivity = ({
parentCounter,
}: {
parentCounter: number;
}) => {
const [counter, setCounter] = useState(0);
useEffect(() => {
console.log('Mount Effect');
// setCounter((prev) => ++prev);
let timerRef = setInterval(() => {
setCounter((prev) => ++prev);
}, 1000);
return () => {
clearInterval(timerRef);
console.log('UnMount Effect');
};
}, []);
useLayoutEffect(() => {
console.log('Mount LayoutEffect');
return () => {
console.log('UnMount LayoutEffect');
};
}, []);
return (
<div>
<p>inside activity</p>
<p>Parent Counter: ${parentCounter}</p>
<p>Count: ${counter}</p>
</div>
);
};
export const BasicActivity = () => {
const [isVisible, setIsVisible] = useState(false);
const [counter, setCounter] = useState(0);
useEffect(() => {
let timerRef = setInterval(() => {
setCounter((prev) => ++prev);
}, 1000);
return () => {
clearInterval(timerRef);
};
}, []);
return (
<div>
<p>Basic Activity</p>
<Activity mode={isVisible ? 'visible' : 'hidden'}>
<ComponentInsideActivity parentCounter={counter} />
</Activity>
<Button
onClick={() => {
setIsVisible((prev) => !prev);
}}
>
Show Content inside activity
</Button>
</div>
);
};
```
When you render *BasicActivity* component, you will see the following behavior
1. Initially, the ComponentInsideActivity is not visible and no effects are created
2. In the Browser DOM you can observe the ComponentInsideActivity is present with `display: none`
3. It also updates the parentCounter every second
Check the code [here](https://stackblitz.com/edit/vitejs-vite-4za4f318?file=src%2Fbasic-activity%2Findex.tsx)
# When to Use
1. The Video Component is an ideal case for Activity Component, as rendering a video is expensive
2. Confetti Component is another good case, as it creates a lot of DOM nodes
3. Any component that's expensive to render like Maps, Charts, etc
4. Prefetching all the contents in the Tabs
The Other examples like `Sidebar`, `Form` where you can save the state is good to have, but with external state management like Zustand, Jotai, Redux, etc it's not a big deal.
# Activity Component implementation
This is what it might look like
```tsx
const Activity = ({mode, children}: {mode: 'hidden' | 'visible', children: ReactChildren}) => {
// Some code implementation to run effects only when mode is visible
// Destroy effects when mode is hidden
// It also runs suspense enabled features when component is hidden, like `use`
return (
<div style={{display: mode === 'hidden' ? 'none' : 'block'}}>
{children}
</div>
);
}
```
# Some Random Thoughts
1. React Navigation and React Native Screens with Freeze Component kind of trying to achieve similar behavior like Activity Commponent
2. Most Drawer Components use similar technique to show and hide component with `display: none` like Activity Component
3. Gorhom Bottom Sheet might benefit from Activity Component