Skip to content

Reactivity ​

The framework provides a unique reactivity system built on top of Vue's reactivity, enabling a clean, class-based developer experience without the need for .value in most cases.

Overview ​

The reactivity system consists of two main parts:

  1. Reactivity Markers: Functions like ref and computed that return lightweight markers during class initialization.
  2. Proxy Wrapper: The applyReactivity function (automatically called by the ViewModel constructor) that replaces these markers with actual Vue reactivity and handles property access.

Reactive System ​

The reactive module defines how reactive fields are declared and processed.

Markers ​

Markers are temporary objects that tell the proxy how to initialize the reactive property.

FunctionReturnsPurpose
ref(initial)RefMarkerRepresents a reactive value.
computed(getter/options)ComputedMarkerRepresents a reactive computed value.

applyReactivity ​

This is the core of the system. It wraps the ViewModel instance in a Proxy.

  • Initialization: When a property marked with a RefMarker or ComputedMarker is first accessed, the proxy creates the corresponding Vue ref or computed and caches it.
  • Getter: Automatically returns the .value of the underlying Vue reference.
  • Setter: Automatically updates the .value of the underlying Vue reference.

This allows you to write this.count++ instead of this.count.value++.

ViewModel Reactive Wrapper ​

The ViewModel class provides protected helper methods that use these markers.

this.ref ​

Creates a reactive property from an initial value.

typescript
export class Counter extends ViewModel {
    public count: number = this.ref(0);

    public increment() {
        this.count++;
    }
}

this.computed ​

Creates a reactive computed property.

typescript
export class Counter extends ViewModel {
    public count: number = this.ref(0);
    public doubleCount: number = this.computed(() => this.count * 2);
}

this.readonly ​

Creates a read-only runtime protected reactive property.

typescript
export class Counter extends ViewModel {
    // It makes sense to declare the property as readonly in typescript as-well
    public readonly name: string;
    
    public constructor(name: string) {
        super();
        
        this.name = this.readonly(name);
    }
}

Key Differences from Standard Vue ​

  1. No .value: Inside the ViewModel (and in the template), you access reactive properties directly.
  2. Class Fields: You must declare reactive properties as class fields assigned to the marker functions.
  3. Proxy-based: Access is intercepted via a Proxy, so standard object operations work as expected on the reactive properties.
  4. Late Initialization: Reactive Vue objects are only created upon first access to the property.