Lifecycle

Run code when components mount and unmount. Set up subscriptions, fetch data, and clean up resources.

onMount

Run code once when a component first renders:

import { onMount } from 'what-framework';

function Chart({ data }) {
  let canvas;

  onMount(() => {
    // Component is now in the DOM
    // canvas ref is available
    const chart = new Chart(canvas, { data });
    console.log('Chart initialized');
  });

  return <canvas ref={el => canvas = el} />;
}

Use onMount for:

  • DOM measurements (element sizes, positions)
  • Setting up third-party libraries
  • Initial data fetching
  • Animations on enter

onCleanup

Register cleanup code to run when the component unmounts:

import { onMount, onCleanup } from 'what-framework';

function WebSocketChat({ roomId }) {
  let socket;

  onMount(() => {
    socket = new WebSocket(`wss://chat.example.com/${roomId}`);
    socket.onmessage = (e) => {
      console.log('Message:', e.data);
    };
  });

  onCleanup(() => {
    // Close connection when component unmounts
    socket?.close();
  });

  return <div className="chat">...</div>;
}

Use onCleanup for:

  • Removing event listeners
  • Closing connections (WebSocket, EventSource)
  • Clearing timers/intervals
  • Canceling pending requests
  • Cleaning up third-party library instances

Common Patterns

Event Listeners

function WindowSize() {
  const size = signal({ width: 0, height: 0 });

  onMount(() => {
    const updateSize = () => {
      size.set({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    };

    updateSize();
    window.addEventListener('resize', updateSize);
  });

  onCleanup(() => {
    window.removeEventListener('resize', updateSize);
  });

  return <p>{() => `${size().width} x ${size().height}`}</p>;
}

Timers

function Clock() {
  const time = signal(new Date());

  onMount(() => {
    const id = setInterval(() => {
      time.set(new Date());
    }, 1000);

    // Return cleanup directly from onMount
    return () => clearInterval(id);
  });

  return <p>{() => time().toLocaleTimeString()}</p>;
}

Third-Party Libraries

function Map({ lat, lng }) {
  let container;
  let map;

  onMount(() => {
    map = L.map(container).setView([lat, lng], 13);
    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
  });

  onCleanup(() => {
    map?.remove();
  });

  return <div ref={el => container = el} style={{ height: '400px' }} />;
}

useEffect Alternative

For React-style lifecycle, use useEffect:

import { useEffect } from 'what-framework';

function Profile({ userId }) {
  const user = signal(null);

  // Runs on mount and when userId changes
  useEffect(() => {
    fetch(`/api/users/${userId}`)
      .then(r => r.json())
      .then(data => user.set(data));

    // Cleanup (optional)
    return () => {
      console.log('Cleanup');
    };
  }, [userId]);  // Dependencies

  return <div>{() => user()?.name}</div>;
}

Comparison

API When to Use
onMount Setup that runs once on mount
onCleanup Cleanup that runs on unmount
useEffect React-style effect with dependencies
effect Reactive effect (auto-tracks signals)

Which to choose?

Use onMount/onCleanup for one-time setup. Use effect for reactive side effects that depend on signals. Use useEffect for React compatibility.