Skip to content

Lifecycle

Lifecycle hooks let you run code at specific points in a component's life.

onMount

Run code when a component is mounted:

tsx
import { signal, onMount } from 'kaori.js';

function Component() {
  const data = signal(null);

  onMount(() => {
    console.log('Component mounted!');
    data.value = fetchData();
  });

  return () => <div>{data.value}</div>;
}

Cleanup with onMount

Return a cleanup function from onMount:

tsx
import { onMount } from 'kaori.js';

function Timer() {
  const count = signal(0);

  onMount(() => {
    const interval = setInterval(() => {
      count.value++;
    }, 1000);

    // Cleanup - called when component unmounts
    return () => {
      clearInterval(interval);
      console.log('Timer cleaned up');
    };
  });

  return () => <div>Time: {count.value}s</div>;
}

onCleanup

Alternative way to register cleanup:

tsx
import { onMount, onCleanup } from 'kaori.js';

function Component() {
  let subscription;

  onMount(() => {
    subscription = subscribe();
  });

  onCleanup(() => {
    subscription.unsubscribe();
  });

  return () => <div>Subscribed</div>;
}

effect

Run side effects that depend on signals:

tsx
import { signal, effect } from 'kaori.js';

function Logger() {
  const count = signal(0);

  effect(() => {
    console.log('Count changed to:', count.value);
    document.title = `Count: ${count.value}`;
  });

  return () => <button onClick={() => count.value++}>Increment</button>;
}

Lifecycle Order

  1. Component function runs (setup)
  2. onMount callbacks queued
  3. Render function runs (first render)
  4. onMount callbacks execute
  5. On updates, render function runs
  6. On unmount, cleanup functions run

Common Patterns

Data Fetching

tsx
function UserProfile(props: { userId: string }) {
  const user = signal(null);
  const loading = signal(true);

  onMount(async () => {
    loading.value = true;
    user.value = await fetchUser(props.userId);
    loading.value = false;
  });

  return () =>
    loading.value ? <div>Loading...</div> : <div>{user.value.name}</div>;
}

Event Listeners

tsx
function ClickTracker() {
  const clicks = signal(0);

  onMount(() => {
    const handleClick = () => clicks.value++;
    window.addEventListener('click', handleClick);

    return () => window.removeEventListener('click', handleClick);
  });

  return () => <div>Global clicks: {clicks.value}</div>;
}

Timers and Intervals

tsx
function Countdown(props: { seconds: number }) {
  const remaining = signal(props.seconds);

  onMount(() => {
    const interval = setInterval(() => {
      if (remaining.value > 0) {
        remaining.value--;
      }
    }, 1000);

    return () => clearInterval(interval);
  });

  return () => <div>{remaining.value}s remaining</div>;
}

Next Steps

Made with 💖 by golok