Counter
The smallest complete ivue class: one piece of mutable state, one derived value, two actions. count is a ref-getter, double is a plain getter — no computed() — and the methods write through .value.
What to notice
doubleallocates nothing. It is a plain getter, re-derived on render — zero bytes per instance, fully reactive through leaf tracking.- Methods are engine-bound.
counter.incrementis safe to pass as a handler directly; its identity is stable.
Related guide pages
- Reactive State — ref-getters, plain getters, the
$-prefixed cache. - Computed & Watch — when
computed()earns its bytes; plainwatchversus$watch. - Components & Templates — one template, one logic owner; the state destructure.
The source
The demo above runs these exact files from the playground:
ts
// Counter.ts — the first class: one ref, one plain getter, two methods.
import { ref } from 'vue';
import { Reactive } from '../../ivue';
class $Counter {
get count() {
return ref(0);
}
// Derived value: a plain getter. No computed() needed for simple math.
get double() {
return this.count.value * 2;
}
increment() {
this.count.value++;
}
reset() {
this.count.value = 0;
}
}
export namespace Counter {
export const $Class = $Counter; // raw — children `extends` this
export let Class = Reactive($Class); // reactive — you `new` this
export type Instance = typeof Class.Instance; // defineExpose type & reactive() interop
}vue
<script setup lang="ts">
import DemoBox from './DemoBox.vue';
import { Counter } from '@examples/counter/Counter';
const counter = new Counter.Class();
// the state destructure
const { count } = counter;
</script>
<template>
<DemoBox
title="Your first class, running"
note="double is a plain getter, not a computed(). It re-derives whenever the component renders."
>
<div class="d-vals">
<div>
<div class="d-k">count</div>
<div class="d-n">{{ count }}</div>
</div>
<div>
<div class="d-k">double · plain getter</div>
<div class="d-n grad">{{ counter.double }}</div>
</div>
</div>
<div class="d-row">
<button class="d-btn primary" type="button" @click="counter.increment">+1</button>
<button class="d-btn" type="button" @click="counter.reset">Reset</button>
</div>
</DemoBox>
</template>Open in StackBlitz ⚡ — the playground boots with this example's route and file active.