Browse documentation

BEYOND QUICK START

Derive a value without duplicating state

Compute a second view of the count and follow both bindings through the component's lifetime.

Counter

0

Twice the count: 0

Start from the Quick Start counter and add a value computed from the count. Inside Counter, map the subject:

export const Counter = component(function* () {
  // Allocate per mounted view so separate counters keep independent state.
  const count = yield* RefSubject.make(0);
  // A read view avoids keeping a second mutable value in sync.
  const doubled = RefSubject.map(count, (value) => value * 2);

doubled observes the count. There is no second mutable value to keep in sync, and the button handlers stay the same. Display it below the controls:

<p>Twice the count: ${doubled}</p>

Each run of component forks its parent’s Scope. That child owns both the generator’s setup and the returned template’s subscriptions and event listeners. When the run ends or its parent closes, those resources are released together; another mounted counter has its own child Scope.

Replace only src/Counter.ts. This version also spells out the button labels as Decrease and Increase. Click Increase twice: the count should be 2 and the doubled value 4.

Complete file

src/Counter.ts
import { component } from "@typed/ui/Component";
import { RefSubject } from "@typed/fx";
import { html } from "@typed/template";

export const Counter = component(function* () {
  // Allocate per mounted view so separate counters keep independent state.
  const count = yield* RefSubject.make(0);
  // A read view avoids keeping a second mutable value in sync.
  const doubled = RefSubject.map(count, (value) => value * 2);

  return html`<section class="counter-demo" aria-label="Counter">
    <h2>Counter</h2>
    <div class="counter-demo__controls">
      <button type="button" onclick=${RefSubject.decrement(count)}>Decrease</button>
      <output aria-live="polite">${count}</output>
      <button type="button" onclick=${RefSubject.increment(count)}>Increase</button>
    </div>
    <p>Twice the count: ${doubled}</p>
  </section>`;
});

Try adding a derived sentence that distinguishes zero, one, and several clicks. Continue with building UI components and Fx services and lifetime for component parameters and shared state.