Reactive Fields
So far, we've learned how to create reactive versions of objects, arrays and other builtin JavaScript objects.
When building your own classes, you can easily use reactive objects in your implementation.
ts
import * asreactive from "@starbeam/collections";export classPerson {readonly #data: {name : string;affiliation : string;};constructor(name : string,affiliation : string) {this.#data =reactive .object ({name ,affiliation });}getcard (): string {return `${this.#data.name } (${this.#data.affiliation })`;}getname (): string {return this.#data.name ;}setname (value : string) {this.#data.name =value ;}getaffiliation (): string {return this.#data.affiliation ;}setaffiliation (value : string) {this.#data.affiliation =value ;}}
ts
import * asreactive from "@starbeam/collections";export classPerson {readonly #data: {name : string;affiliation : string;};constructor(name : string,affiliation : string) {this.#data =reactive .object ({name ,affiliation });}getcard (): string {return `${this.#data.name } (${this.#data.affiliation })`;}getname (): string {return this.#data.name ;}setname (value : string) {this.#data.name =value ;}getaffiliation (): string {return this.#data.affiliation ;}setaffiliation (value : string) {this.#data.affiliation =value ;}}
From the perspective of external code, these getters behave like normal properties, and can be accessed like any other JavaScript object.
If card
is rendered reactively, any changes to #data.name
or #data.affiliation
(even when made through the getters and setters) will be reflected in the UI.
Enter Reactive Fields
While this works just fine, it can get tedious and repetitive.
Instead, you can create reactive fields using the @reactive
decorator.
ts
export classPerson {@tracked accessorname : string;@tracked accessoraffiliation : string;constructor(name : string,affiliation : string) {this.name =name ;this.affiliation =affiliation ;}getcard (): string {return `${this.name } (${this.affiliation })`;}}
ts
export classPerson {@tracked accessorname : string;@tracked accessoraffiliation : string;constructor(name : string,affiliation : string) {this.name =name ;this.affiliation =affiliation ;}getcard (): string {return `${this.name } (${this.affiliation })`;}}
From the perspective of external code, these fields also work like normal JavaScript properties, and reactively rendering card
will update whenever either of the fields change.
While you could get along just fine without reactive fields, they make writing reactive classes much more convenient, and let you focus on your application logic rather than the mechanics of getters and setters.
Do More With Reactive Fields
In addition to @tracked property
, you can also use @reactive
on private fields (@reactive #name
), and any changes you make to the private fields will invalidate any getters, setters or methods that access them.
You can also use @reactive
together with decorators like @readonly
from any library of standard JavaScript decorators.
Finally, the @reactive
decorator also works seamlessly with TypeScript 5+, including type support, without the need for any special experimental flags.
Build Tools
While tsc
, swc
and babel
support compiling standard JavaScript decorators, your build tool may not (yet) support them.
We hope to see rapid ecosystem adoption of this standard feature in the near future (and then we'll be able to remove this box).