Skip to content

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 ​

  • double allocates nothing. It is a plain getter, re-derived on render — zero bytes per instance, fully reactive through leaf tracking.
  • Methods are engine-bound. counter.increment is safe to pass as a handler directly; its identity is stable.

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 &middot; 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.

Released under the MIT License.