@vueent/reactive

Typescript decorators for Vue.js Composition API

Usage no npm install needed!

<script type="module">
  import vueentReactive from 'https://cdn.skypack.dev/@vueent/reactive';
</script>

README

@vueent/reactive

This library is a part of VueentT project, but it can be used independently. It is a set of decorators which allows to use ref and computed as class properties and forget about checks like this:

const value = isRef(this.field) ? this.field.value : this.field);

Installation

npm install -D @vueent/reactive

This library has Vue 3 or Vue composition API plugin for Vue 2 peer dependency, it means that your have to add this dependencies into your project (package.json) manually.

Usage

The package provides two decorators. tracked makes a ref from the class field. calculated wrapps a getter/setter pair and makes a computed property.

::: warning isRef and toRef functions don't work with decorated fields, but decorated fields are not mutated within reactive objects as a benefit. :::

Let's look at the trivial example:

import { tracked, calculated } from '@vueent/reactive';

class MyClass {
  @tracked public num = 2;
  @tracked public factor = 3;

  @calculated public get mul() {
    return this.num * this.factor;
  }
}

const my = new MyClass();

const myObj = reactive({ my });

myObj.my.factor = 4;

console.log(myObj.my.mul); // 8 - everything works fine

You may try to write the following code, but it won't work:

class InvalidClass {
  public num = ref(2);
  public factor = ref(3);
  readonly mul = computed(() => this.num.value * this.factor.value);
}

const invalid = new InvalidClass();

const invalidObj = reactive({ invalid });

invalidObj.invalid.factor = 4;
console.log(invalidObj.invalid.mul);
// Ooops! throws an error, because this.num is a `number`, not `{ value: number }`

The brutal solution:

class MyClass {
  private _num: Ref<number> | number = ref(2);
  private _factor: Ref<number> | number = ref(3);
  private readonly _mul: ComputedRef<number> | number> = computed(() => this.num * this.factor);

  public get num() {
    return isRef(this._num) ? this._num.value : this._num;
  }

  public set num(value: number) {
    isRef(this._num) ? (this._num.value = value) : (this._num = value);
  }

  public get factor() {
    return isRef(this._factor) ? this._factor.value : this._factor;
  }

  public set factor(value: number) {
    return isRef(this._factor) ? (this._factor.value = value) : (this._factor = value);
  }

  public get mul() {
    return isRef(this._mul) ? this._mul.value : this._mul;
  }
}

const my = new MyClass();

const myObj = reactive({ my });

myObj.my.factor = 4;

console.log(myObj.my.mul); // 8 - everything works fine

LICENSE

MIT