Counter
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 mounted counter owns its state and subscriptions. For the resource contract, see component lifetime.
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 { RefSubject } from "@typed/fx";
import { component, 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. Then build TodoMVC to use derived values in a complete client-side application.