---
title: Tasks and Lifecycle | Components
contributors:
  - mhevery
  - manucorporat
  - wtlin1228
  - AnthonyPAlicea
  - saisrikardumpeti
  - sreeisalso
  - brunocrosier
  - harishkrishnan24
  - gioboa
  - bodhicodes
  - zanettin
  - blackpr
  - mrhoodz
  - ehrencrona
  - julianobrasil
  - adamdbradley
  - aendel
  - jemsco
  - varixo
  - wmertens
updated_at: '2026-02-10T12:00:00Z'
created_at: '2023-03-31T02:40:50Z'
---

import CodeSandbox from '../../../../../components/code-sandbox/index.tsx';
import { Note, LongNote } from '~/components/note/note';


# Tasks

Tasks are meant for running asynchronous operations as part of component initialization or change of component state.

<LongNote title="Tasks vs useEffect()">
Tasks are similar to `useEffect()` in React, but there are enough differences that we did not want to call them the same so as not to bring preexisting expectations about how they work. The main differences are:

- Tasks are asynchronous.
- Tasks run on server and browser.
- Tasks run before rendering and can block rendering.
- Subsequent task re-executions (when tracked state changes) block rendering by default, but can be configured to not block DOM updates with `deferUpdates: false`.
</LongNote>

`useTask$()` should be your default go-to API for running either synchronous or asynchronous work as part of component initialization or state change. It is only when you can't achieve what you need with `useTask$()` that you should consider using `useVisibleTask$()`.

The basic use case for `useTask$()` is to perform work on component initialization. `useTask$()` has these properties:
- It can run on either the server or in the browser.
- It runs before the initial rendering and blocks the initial render.
- If multiple tasks are running then they are run sequentially in the order they were registered. An asynchronous task will block the next task from running until it completes.
- By default, subsequent re-executions (when tracked state changes) do block DOM updates unless `deferUpdates: false` is specified.

Tasks can also be used to perform work when a component state changes. In this case, the task will rerun every time the tracked state changes. See: [`track()`](#track).

Sometimes a task needs to run only on the browser and after rendering, in that case, you should use [`useVisibleTask$()`](#usevisibletask).

<Note>If you need to fetch data asynchronously and not block rendering, you should use [`useComputed$()`](/docs/core/state/#usecomputed) with an async function. It does not block rendering while the async value is being resolved.</Note>

## Lifecycle
Resumability is "Lazy execution", it's the ability to build the "framework state" (component boundaries, etc) on the server, and have it exist on the client without re-executing the framework again.

The application environment—whether client-side or server-side—is determined by user interactions. In server-side rendering, the application initially renders on the server.
When the user interacts with the application, it resumes on the client-side, continuing from the state left by the server. This approach ensures efficient and responsive user experiences by leveraging both environments based on interaction.

<Note>For systems that use hydration, the execution of the application happens twice. Once on a server (SSR/SSG) and once on the browser (hydration). This is why many frameworks have "effects" which only execute on the browser. That means that the code that runs on the server is different than the code that runs on the browser. Qwik execution is unified, meaning if the code has already been executed on the server, it does not re-execute it on the browser.</Note>

**In Qwik, there are only 3 lifecycle stages:**

- `Task` - run before rendering and when tracked state changes. `Tasks` run sequentially, and block each other. They also can block rendering.
- `Render` - runs after `TASK` and before `VisibleTask`
- `VisibleTask` - runs after `Render` and when the component becomes visible

<div style="background:white;border:1.6px solid #45c6ff;border-radius:16px;box-shadow:6px 6px 0 0 #b2e4ff;padding:24px;overflow:clip">
<svg viewBox="0 0 720 160" fill="none" xmlns="http://www.w3.org/2000/svg" style="width:100%;max-width:720px;display:block;margin:0 auto" role="img" aria-label="Task lifecycle diagram: useTask$ runs on server or browser, then renders, then useVisibleTask$ runs on browser">
  <rect x="40" y="20" width="130" height="40" rx="8" fill="#E4D7FF" stroke="#AE76FE" stroke-width="1.6"/>
  <text x="105" y="45" text-anchor="middle" font-family="Ubuntu Sans,sans-serif" font-size="14" font-weight="600" fill="#451D73">useTask$</text>
  <rect x="270" y="20" width="110" height="40" rx="8" fill="#C4EAFF" stroke="#45C6FF" stroke-width="1.6"/>
  <text x="325" y="45" text-anchor="middle" font-family="Ubuntu Sans,sans-serif" font-size="14" font-weight="700" fill="#003950">RENDER</text>
  <rect x="490" y="20" width="180" height="40" rx="8" fill="#D7F1FF" stroke="#00ABE4" stroke-width="1.6"/>
  <text x="580" y="45" text-anchor="middle" font-family="Ubuntu Sans,sans-serif" font-size="14" font-weight="600" fill="#004863">useVisibleTask$</text>
  <line x1="170" y1="40" x2="270" y2="40" stroke="#293749" stroke-width="1.6" marker-end="url(#arrow)"/>
  <line x1="380" y1="40" x2="490" y2="40" stroke="#293749" stroke-width="1.6" marker-end="url(#arrow)"/>
  <line x1="325" y1="60" x2="325" y2="100" stroke="#293749" stroke-width="1.6" stroke-dasharray="6 4"/>
  <text x="325" y="120" text-anchor="middle" font-family="Ubuntu Sans,sans-serif" font-size="12" font-weight="600" fill="#5A6A7D">pause | resume</text>
  <line x1="20" y1="90" x2="700" y2="90" stroke="#B3C5DB" stroke-width="1"/>
  <text x="165" y="150" text-anchor="middle" font-family="Ubuntu Sans,sans-serif" font-size="11" font-weight="600" fill="#708094">SERVER or BROWSER</text>
  <text x="530" y="150" text-anchor="middle" font-family="Ubuntu Sans,sans-serif" font-size="11" font-weight="600" fill="#708094">BROWSER</text>
  <defs>
    <marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
      <path d="M 0 0 L 10 5 L 0 10 z" fill="#293749"/>
    </marker>
  </defs>
</svg>
</div>

**SERVER**: Usually **the life of a component starts on the server** (during SSR or SSG), in that case, the `useTask$` and `RENDER` will run in the server, and then the `VisibleTask` will run in the browser, after the component is visible.

<Note>Because the component was mounted in the server, **only useVisibleTask$() runs in the browser**. This is because the browser continues the same lifecycle, that was paused in the server right after the render and resumed in the browser.</Note>

**BROWSER**: When a component is first mounted or rendered in the browser, for example when a user navigates to a new page in a Single Page Application (SPA) or when a "modal" component initially appears on the page, the lifecycle will proceed as follows:

<div style="background:white;border:1.6px solid #45c6ff;border-radius:16px;box-shadow:6px 6px 0 0 #b2e4ff;padding:24px;overflow:clip">
<svg viewBox="0 0 720 120" fill="none" xmlns="http://www.w3.org/2000/svg" style="width:100%;max-width:720px;display:block;margin:0 auto" role="img" aria-label="Browser-only lifecycle: useTask$, then render, then useVisibleTask$ all run in browser">
  <rect x="100" y="20" width="130" height="40" rx="8" fill="#E4D7FF" stroke="#AE76FE" stroke-width="1.6"/>
  <text x="165" y="45" text-anchor="middle" font-family="Ubuntu Sans,sans-serif" font-size="14" font-weight="600" fill="#451D73">useTask$</text>
  <rect x="310" y="20" width="110" height="40" rx="8" fill="#C4EAFF" stroke="#45C6FF" stroke-width="1.6"/>
  <text x="365" y="45" text-anchor="middle" font-family="Ubuntu Sans,sans-serif" font-size="14" font-weight="700" fill="#003950">RENDER</text>
  <rect x="500" y="20" width="160" height="40" rx="8" fill="#D7F1FF" stroke="#00ABE4" stroke-width="1.6"/>
  <text x="580" y="45" text-anchor="middle" font-family="Ubuntu Sans,sans-serif" font-size="14" font-weight="600" fill="#004863">useVisibleTask$</text>
  <line x1="230" y1="40" x2="310" y2="40" stroke="#293749" stroke-width="1.6" marker-end="url(#arrow3)"/>
  <line x1="420" y1="40" x2="500" y2="40" stroke="#293749" stroke-width="1.6" marker-end="url(#arrow3)"/>
  <line x1="60" y1="80" x2="700" y2="80" stroke="#B3C5DB" stroke-width="1"/>
  <text x="380" y="105" text-anchor="middle" font-family="Ubuntu Sans,sans-serif" font-size="11" font-weight="600" fill="#708094">BROWSER</text>
  <defs>
    <marker id="arrow3" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
      <path d="M 0 0 L 10 5 L 0 10 z" fill="#293749"/>
    </marker>
  </defs>
</svg>
</div>

<Note>The lifecycle is exactly the same, but this time all the hooks run in the browser, and not in the server.</Note>

## `useTask$()`

- **When:** BEFORE component's first render, and when tracked state changes
- **Times:** at least once
- **Platform:** server and browser

`useTask$()` registers a hook to be executed upon component creation, it will run at least once either in the server or in the browser, depending on where the component is initially rendered.

### Task options

`useTask$()` accepts an optional second parameter of type `TaskOptions` to configure the task behavior.

```typescript
interface TaskOptions {
  deferUpdates?: boolean;
}
```

#### `deferUpdates`

The `deferUpdates` option controls whether subsequent task re-executions (when tracked state changes) should block DOM updates.

**Default behavior (`deferUpdates: false` or not specified):**
- **Initial render**: The task blocks rendering (same as default)
- **Subsequent runs**: The task blocks DOM updates until it completes - the journal flush is deferred until the task finishes

**With `deferUpdates: true`:**
- **Initial render**: The task blocks rendering (runs before the component renders for the first time)
- **Subsequent runs**: The task runs asynchronously without blocking DOM updates

Additionally, this task can be reactive and will re-execute when **tracked** [state](/docs/(qwik)/core/state/index.mdx) changes.

**Notice that any subsequent re-execution of the task will always happen in the browser**, because reactivity is a browser-only thing.

<div style="background:white;border:1.6px solid #45c6ff;border-radius:16px;box-shadow:6px 6px 0 0 #b2e4ff;padding:24px;overflow:clip">
<svg viewBox="0 0 720 200" fill="none" xmlns="http://www.w3.org/2000/svg" style="width:100%;max-width:720px;display:block;margin:0 auto" role="img" aria-label="Task re-execution lifecycle: useTask$ with track runs on server, renders, then on browser click triggers re-execution">
  <rect x="20" y="20" width="160" height="40" rx="8" fill="#E4D7FF" stroke="#AE76FE" stroke-width="1.6"/>
  <text x="100" y="45" text-anchor="middle" font-family="Ubuntu Sans,sans-serif" font-size="13" font-weight="600" fill="#451D73">useTask$(track)</text>
  <rect x="240" y="20" width="110" height="40" rx="8" fill="#C4EAFF" stroke="#45C6FF" stroke-width="1.6"/>
  <text x="295" y="45" text-anchor="middle" font-family="Ubuntu Sans,sans-serif" font-size="14" font-weight="700" fill="#003950">RENDER</text>
  <rect x="420" y="20" width="100" height="40" rx="8" fill="#FFE7E6" stroke="#FF7077" stroke-width="1.6"/>
  <text x="470" y="45" text-anchor="middle" font-family="Ubuntu Sans,sans-serif" font-size="14" font-weight="600" fill="#670015">CLICK</text>
  <rect x="540" y="20" width="160" height="40" rx="8" fill="#E4D7FF" stroke="#AE76FE" stroke-width="1.6"/>
  <text x="620" y="45" text-anchor="middle" font-family="Ubuntu Sans,sans-serif" font-size="13" font-weight="600" fill="#451D73">useTask$(track)</text>
  <line x1="180" y1="40" x2="240" y2="40" stroke="#293749" stroke-width="1.6" marker-end="url(#arrow2)"/>
  <line x1="350" y1="40" x2="420" y2="40" stroke="#293749" stroke-width="1.6" marker-end="url(#arrow2)"/>
  <line x1="520" y1="40" x2="540" y2="40" stroke="#293749" stroke-width="1.6" marker-end="url(#arrow2)"/>
  <path d="M 620 60 L 620 85 C 620 95 610 95 600 95 L 480 95 C 470 95 470 85 470 75 L 470 60" stroke="#AE76FE" stroke-width="1.6" fill="none" marker-end="url(#arrow2purple)" stroke-dasharray="6 4"/>
  <text x="545" y="108" text-anchor="middle" font-family="Ubuntu Sans,sans-serif" font-size="11" font-weight="600" fill="#6A25B3">state change → re-execute</text>
  <line x1="295" y1="60" x2="295" y2="140" stroke="#293749" stroke-width="1.6" stroke-dasharray="6 4"/>
  <text x="295" y="158" text-anchor="middle" font-family="Ubuntu Sans,sans-serif" font-size="12" font-weight="600" fill="#5A6A7D">pause | resume</text>
  <line x1="10" y1="130" x2="710" y2="130" stroke="#B3C5DB" stroke-width="1"/>
  <text x="150" y="190" text-anchor="middle" font-family="Ubuntu Sans,sans-serif" font-size="11" font-weight="600" fill="#708094">SERVER</text>
  <text x="500" y="190" text-anchor="middle" font-family="Ubuntu Sans,sans-serif" font-size="11" font-weight="600" fill="#708094">BROWSER</text>
  <defs>
    <marker id="arrow2" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
      <path d="M 0 0 L 10 5 L 0 10 z" fill="#293749"/>
    </marker>
    <marker id="arrow2purple" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
      <path d="M 0 0 L 10 5 L 0 10 z" fill="#AE76FE"/>
    </marker>
  </defs>
</svg>
</div>

<Note>If `useTask$()` does not track any state, it will run **exactly once**, either in the server **or** in the browser (**not both**), depending where the component is initially rendered. Effectively behaving like an "on-mount" hook.</Note>

`useTask$()` will block the rendering of the component until after its async callback resolves. Tasks execute sequentially even if they are asynchronous (only one task executes at a time within a component). Subsequent re-executions (when tracking state changes) run asynchronously by default and block rendering unless `deferUpdates: false` is set.

Take a look at the simplest use case of the task to run some asynchronous work on component initialization:

<CodeSandbox src="/src/routes/demo/tasks/use-task/index.tsx">
```tsx
import { component$, useSignal, useTask$ } from '@qwik.dev/core';

export default component$(() => {
  const fibonacci = useSignal<number[]>();

  useTask$(async () => {
    const size = 40;
    const array = [];
    array.push(0, 1);
    for (let i = array.length; i < size; i++) {
      array.push(array[i - 1] + array[i - 2]);
      await delay(100);
    }
    fibonacci.value = array;
  });

  return <p>{fibonacci.value?.join(', ')}</p>;
});

const delay = (time: number) => new Promise((res) => setTimeout(res, time));
```
</CodeSandbox>

<LongNote title="Fibonacci Example Explained">
- The `useTask$()` computes the fibonacci number one entry per 100 ms. So 40 entries take 4 seconds to render.
  - The `useTask$()` executes on the server as part of the SSR (the result may be cached in CDN.)
  - Because the `useTask$()` blocks rendering, the rendered HTML page takes 4 seconds to render.
- Because this task has no `track()` it will never rerun, making it effectively an initialization code.
  - Because this component only renders on the server, the `useTask$()` will never be downloaded or run on the browser.
</LongNote>

<Note>`useTask$()` runs on the server **BEFORE** the actual rendering. Therefore if you need to do DOM manipulation, use [`useVisibleTask$()`](#usevisibletask) instead, which runs on the browser after rendering.</Note>

Use `useTask$()` when you need to:
- Run async tasks before rendering
- Run code only once before the component is first rendered  
- Programmatically run side-effect code when state changes

<Note>If you're thinking about loading data using `fetch()` inside of `useTask$`, consider using [`useComputed$()`](/docs/core/state/#usecomputed) with an async function instead. This API is more convenient.</Note>

### On mount

In Qwik, there isn't a specific "mount" step like in some other frameworks. Instead, components just start up directly where they're needed, either on a web server or in your browser. 
This is without the inner track function, which is used to monitor specific pieces of data.

`useTask$` runs always at least once when the component is first mounted.

```tsx {5-8}
import { component$, useTask$ } from '@qwik.dev/core';

export default component$(() => {

  useTask$(async () => {
    // A task without `track` any state effectively behaves like a `on mount` hook.
    console.log('Runs once when the component mounts in the server OR client.');
  });

  return <div>Hello</div>;
});
```

One unique aspect of Qwik, is that components are mounted only **once** across the server and client. This is a property of resumability. What this means is that if `useTask$` is executed during Server-Side Rendering (SSR), it will not run again in the browser because Qwik does not perform hydration.

### `track()`

There are times when it is desirable to re-run a task when a component state changes. This is done by using the `track()` function. The `track()` function allows you to set up a dependency on a component's state when initially rendered on the server, and then re-execute the task when the state changes in the browser.

Track accepts signals, stores and functions. It returns the value of the signal, the store itself, or the function call result.

When you pass a store, the track will be called when the store gets or removes properties as well as mutations of properties.
Note that deep store updates don't mutate the store itself, so `store[item].count++` will not trigger an update. Instead, you should individually track each `store[item]` (which are also automatically created stores).

During SSR, each component will wait until all tasks are completed before outputting the HTML for that component. So a task can be called multiple times during SSR if the tracked state changes due to other tasks.

<Note>Use [`useComputed$()`](/docs/core/state/#usecomputed) to compute a new state from existing state. For async derivations (like search-as-you-type), pass it an async function and cancel in-flight work with `cleanup()` or the provided `abortSignal`.</Note>

<CodeSandbox src="/src/routes/demo/tasks/track/index.tsx" >
```tsx
import { component$, isServer, useSignal, useTask$ } from '@qwik.dev/core';

export default component$(() => {
  const text = useSignal('Initial text');
  const delayText = useSignal('');

  useTask$(({ track }) => {
    // Passing a signal directly is more efficient than using a function.
    const newText = track(text);
    const update = () => (delayText.value = newText);
    isServer
      ? update() // don't delay on server render value as part of SSR
      : delay(500).then(update); // Delay in browser
  });

  return (
    <section>
      <label>
        Enter text: <input bind:value={text} />
      </label>
      <p>Delayed text: {delayText}</p>
    </section>
  );
});

const delay = (time: number) => new Promise((res) => setTimeout(res, time));
```
</CodeSandbox>

<LongNote title="How track() Works Across Server and Browser">
On the server:

- The `useTask$()` runs on the server and the `track()` function sets up a subscription on the `text` signal.
- The page is rendered.

On the browser:
- The `useTask$()` does not have to run or be downloaded eagerly because Qwik knows that the task is subscribed to the `text` signal from the server execution.
- When the user types in the input box, the `text` signal changes. Qwik knows that the `useTask$()` is subscribed to the `text` signal and it is at this time that the `useTask$()` closure is brought into the JavaScript VM to be executed.

The `useTask$()` blocks rendering until it completes. If you don't want to block rendering, make sure that the task is resolved, and run the delay work on a separate unconnected promise. In this example, we don't await `delay()` because it would block rendering.
</LongNote>

<Note>Sometimes it is required to only run code either in the server or in the client. This can be achieved by using the `isServer` and `isBrowser` booleans exported from `@qwik.dev/core` as shown above.</Note>


### `track()` as a function

In the above example, `track()` was used to track a specific signal. However, `track()` can also be used as a function to track multiple signals at once.

<CodeSandbox src="/src/routes/demo/tasks/track-fn/index.tsx" >
```tsx
import { component$, isServer, useSignal, useTask$ } from '@qwik.dev/core';

export default component$(() => {
  const isUppercase = useSignal(false);
  const text = useSignal('');
  const delayText = useSignal('');

  useTask$(({ track }) => {
    const value = track(() =>
      isUppercase.value ? text.value.toUpperCase() : text.value.toLowerCase()
    );
    const update = () => (delayText.value = value);
    isServer
      ? update() // don't delay on server render value as part of SSR
      : delay(500).then(update); // Delay in browser
  });

  return (
    <section>
      <label>
        Enter text: <input bind:value={text} />
      </label>
      <label>
        Is uppercase? <input type="checkbox" bind:checked={isUppercase} />
      </label>
      <p>Delay text: {delayText}</p>
    </section>
  );
});

function delay(time: number) {
  return new Promise((resolve) => setTimeout(resolve, time));
}
```
</CodeSandbox>

<Note>In this example, the `track()` takes a function that not only reads the signal but also transforms its value to uppercase/lowercase. The `track()` subscribes to multiple signals and computes their value.</Note>

### `cleanup()`

Sometimes when running a task, cleanup work needs to be performed. When a new task is triggered, the previous task's `cleanup()` callback is invoked. This callback is also invoked when the component is removed from the DOM.

<LongNote title="cleanup() Behavior">
- The `cleanup()` function is not invoked when the task is completed. It is only invoked when a new task is triggered or when the component is removed.
- The `cleanup()` function is invoked on the server after the applications are serialized into HTML.
- The `cleanup()` function is not transferable from server to browser. Cleanup is meant to release resources on the VM where it is running. It is not meant to be transferred to the browser.
</LongNote>

This example shows how to implement a debounce feature using the `cleanup()` function.

<CodeSandbox src="/src/routes/demo/tasks/cleanup/index.tsx" >
```tsx
import { component$, useSignal, useTask$ } from '@qwik.dev/core';

export default component$(() => {
  const text = useSignal('');
  const debounceText = useSignal('');

  useTask$(({ track, cleanup }) => {
    const value = track(() => text.value);
    const id = setTimeout(() => (debounceText.value = value), 500);
    cleanup(() => clearTimeout(id));
  });

  return (
    <section>
      <label>
        Enter text: <input bind:value={text} />
      </label>
      <p>Debounced text: {debounceText}</p>
    </section>
  );
});
```
</CodeSandbox>

## `useVisibleTask$()`

Sometimes a task needs to run only on the browser and after rendering, in that case, you should use `useVisibleTask$()`. The `useVisibleTask$()` is similar to `useTask$()` but it only runs on the browser and after initial rendering. `useVisibleTask$()` registers a hook to be executed when the component becomes visible in the viewport, it will run at least once in the browser, and it can be reactive and re-execute when some **tracked** [state](/docs/(qwik)/core/state/index.mdx) changes.

`useVisibleTask$()` has these properties:

- runs on the client only.
- eagerly executes code on the client when the component becomes visible.
- runs after initial rendering.
- does not block rendering.

<LongNote title="Caution: useVisibleTask$() as a Last Resort">
The `useVisibleTask$()` should be used as a last resort, because it eagerly executes code on the client. Qwik, through [resumability](), goes out of its way to delay the execution of code on the client, and `useVisibleTask$()` is an escape hatch that should be used with caution. See [Best Practices](/docs/(qwikrouter)/guides/best-practices/index.mdx#dont-register-events-eagerly-with-usevisibletask) for more details.
If you need to run a task on a client consider `useTask$()` with a server guard.

<CodeSandbox src="/src/routes/demo/tasks/track-server-guard/index.tsx">
```tsx
import { component$, isServer, useSignal, useTask$ } from '@qwik.dev/core';

export default component$(() => {
  const text = useSignal('Initial text');
  const isBold = useSignal(false);

  useTask$(({ track }) => {
    track(() => text.value);
    if (isServer) {
      return; // Server guard
    }
    isBold.value = true;
    delay(1000).then(() => (isBold.value = false));
  });

  return (
    <section>
      <label>
        Enter text: <input bind:value={text} />
      </label>
      <p style={{ fontWeight: isBold.value ? 'bold' : 'normal' }}>
        Text: {text}
      </p>
    </section>
  );
});

const delay = (time: number) => new Promise((res) => setTimeout(res, time));
```
</CodeSandbox>

In the above example, the `useTask$()` is guarded by `isServer`. The `track()` function is placed before the guard, which
allows the server to set up the subscription without executing any code on the server. The client
then executes the `useTask$()` once the `text` signal changes.
</LongNote>

This example shows how to use `useVisibleTask$()` to initialize a clock on the browser only when the clock component becomes visible.

<CodeSandbox src="/src/routes/demo/tasks/use-visible-task/index.tsx" >
```tsx
import {
  component$,
  useSignal,
  useVisibleTask$,
  type Signal,
} from '@qwik.dev/core';

export default component$(() => {
  const isClockRunning = useSignal(false);

  return (
    <>
      <div style="position: sticky; top:0">
        Scroll to see clock. (Currently clock is
        {isClockRunning.value ? ' running' : ' not running'}.)
      </div>
      <div style="height: 200vh" />
      <Clock isRunning={isClockRunning} />
    </>
  );
});

const Clock = component$<{ isRunning: Signal<boolean> }>(({ isRunning }) => {
  const time = useSignal('paused');
  useVisibleTask$(({ cleanup }) => {
    isRunning.value = true;
    const update = () => (time.value = new Date().toLocaleTimeString());
    const id = setInterval(update, 1000);
    cleanup(() => clearInterval(id));
  });
  return <div>{time}</div>;
});
```
</CodeSandbox>

<Note>The clock's `useVisibleTask$()` does not run until the `<Clock>` component becomes visible. The default behavior of `useVisibleTask$()` is to run the task when the component becomes visible. This behavior is implemented through [intersection observers](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API).</Note>

<Note>The [intersection observers](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) will not run on components that are not considered visible such as `<audio />`.</Note>

### Option `eagerness`

At times it is desirable to run `useVisibleTask$()` eagerly as soon as the application is loaded in the browser. In that case, the `useVisibleTask$()` needs to run in eager mode. This is done by using the `{ strategy: 'document-ready' }`.

<CodeSandbox src="/src/routes/demo/tasks/use-visible-task-eager/index.tsx">
```tsx
import {
  component$,
  useSignal,
  useVisibleTask$,
  type Signal,
} from '@qwik.dev/core';

export default component$(() => {
  const isClockRunning = useSignal(false);

  return (
    <>
      <div style="position: sticky; top:0">
        Scroll to see clock. (Currently clock is
        {isClockRunning.value ? ' running' : ' not running'}.)
      </div>
      <div style="height: 200vh" />
      <Clock isRunning={isClockRunning} />
    </>
  );
});

const Clock = component$<{ isRunning: Signal<boolean> }>(({ isRunning }) => {
  const time = useSignal('paused');
  useVisibleTask$(
    ({ cleanup }) => {
      isRunning.value = true;
      const update = () => (time.value = new Date().toLocaleTimeString());
      const id = setInterval(update, 1000);
      cleanup(() => clearInterval(id));
    },
    { strategy: 'document-ready' }
  );
  return <div>{time}</div>;
});
```
</CodeSandbox>

<Note>In this example, the clock starts running immediately on the browser regardless of whether it is visible or not.</Note>

### Advanced: Time of running, and managing visibility with CSS

Internally, `useVisibleTask$` is implemented by adding an attribute to the first rendered component (either the returned component or in the case of a Fragment, its first child).  With the standard `eagerness`, this means that if the first rendered component is hidden, the task will not run.

This means that you can use CSS to influence when the task runs. For example, if the task should only run on a mobile device, you can return a `<div class="md:invisible" />` (in the case of Tailwind CSS).

This also means you cannot unhide a component using a visible task; for that you can return a Fragment:

```tsx
return (<>
  <div />
  <MyHiddenComponent hidden={!showSignal.value} />
</>)
```

## Use Hook Rules

When using lifecycle hooks, you must adhere to the following rules:

- They can only be called at the root level of `component$` (not inside conditional blocks)
- They can only be called at the root of another `use*` method, allowing for composition.

```tsx
useHook(); // <-- ❌ does not work

export default component$(() => {
  useCustomHook(); // <-- ✅ does work
  if (condition) {
    useHook(); // <-- ❌ does not work
  }
  useTask$(() => {
    useNavigate(); // <-- ❌ does not work
  });
  const myQrl = $(() => useHook()); // <-- ❌ does not work
  return <button onClick$={() => useHook()}></button>; // <-- ❌ does not work
});

function useCustomHook() {
  useHook(); // <-- ✅ does work
  if (condition) {
    useHook(); // <-- ❌ does not work
  }
}
```
