@vueent/reactive
TypeScript icon, indicating that this package has built-in type declarations

0.6.0 • Public • Published

@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

[!IMPORTANT]

This library has Vue 3, Vue 2.7 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

[!IMPORTANT]

As of TypeScript 4.3, support of experimental decorators must be allowed by the following tsconfig.json options:

{
  "compilerOptions": {
    // ...
    "moduleResolution": "node",
    "useDefineForClassFields": false,
    "experimentalDecorators": true
  }
}

Experimantal decorators are still available as legacyTracked and legacyCalculated.

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

[!CAUTION]

calculated decorator must be applied to both getter and setter method, whereas legacyCalculated decorator must only be applied to the getter.

[!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 accessor num = 2;
  @tracked public accessor 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

Package Sidebar

Install

npm i @vueent/reactive

Weekly Downloads

4

Version

0.6.0

License

MIT

Unpacked Size

56.9 kB

Total Files

10

Last publish

Collaborators

  • devoter