Skip to content
On this page

Our Guiding Principle

Starbeam's Core Principle

If you model your reactive data like any other data, you can build reliable reactive UIs with the skills you already have.

We believe that reactive programming should feel exactly like regular programming.

Reactive UI frameworks have a way of describing reactive inputs and a way of describing an output in terms of those inputs, which the framework automatically keeps up to date.

Starbeam's APIs for input data are annotated versions of normal JavaScript data structures, and you use normal JavaScript functions for all of your computation.

What That Means in Practice

Here are some examples of how Starbeam's principles work in practice, especially in ways that might be different from other reactive frameworks you're familiar with.

Data Updates Happen Immediately

When you update a reactive value, the reactive update happens immediately. Any code that accesses the reactive value will see the new value.

There are no exceptions.

This means that you can write elaborate abstractions or libraries that are built on reactive values, and they will behave exactly as you expect regardless of how they're used by app code.

You Derive State Using Normal Functions

If you want to compute a value from reactive values, you just use functions.

You can also use getters, methods, and the new private versions of those features to access the reactive values. You can mix and match JavaScript features however you want. Once you've used a reactive value to store your state, you don't have to think about reactivity as you compute values.

Example

tsx
import { reactive } from "@starbeam/js";
 
export class People {
#people = reactive.array([]);
 
add(name, location) {
this.#people.push({ name, location });
}
 
byLocation(location) {
return this.#people.filter(
(person) => person.location === location,
);
}
 
update(name, location) {
const index = this.#people.findIndex(
(person) => person.name === name,
);
 
if (index !== -1) {
this.#people[index] = { name, location };
}
}
}
tsx
import { reactive } from "@starbeam/js";
 
export class People {
#people = reactive.array([]);
 
add(name, location) {
this.#people.push({ name, location });
}
 
byLocation(location) {
return this.#people.filter(
(person) => person.location === location,
);
}
 
update(name, location) {
const index = this.#people.findIndex(
(person) => person.name === name,
);
 
if (index !== -1) {
this.#people[index] = { name, location };
}
}
}
tsx
import { reactive } from "@starbeam/js";
 
export class People {
#people: Person[] = reactive.array([]);
 
add(name: string, location: string) {
this.#people.push({ name, location });
}
 
byLocation(location: string) {
return this.#people.filter(
(person) => person.location === location,
);
}
 
update(name: string, location: string) {
const index = this.#people.findIndex(
(person) => person.name === name,
);
 
if (index !== -1) {
this.#people[index] = { name, location };
}
}
}
 
interface Person {
name: string;
location: string;
}
tsx
import { reactive } from "@starbeam/js";
 
export class People {
#people: Person[] = reactive.array([]);
 
add(name: string, location: string) {
this.#people.push({ name, location });
}
 
byLocation(location: string) {
return this.#people.filter(
(person) => person.location === location,
);
}
 
update(name: string, location: string) {
const index = this.#people.findIndex(
(person) => person.name === name,
);
 
if (index !== -1) {
this.#people[index] = { name, location };
}
}
}
 
interface Person {
name: string;
location: string;
}

In this example, we built a People class that stores a list of people. We used a private field to store a reactive array.

INFO

We could have stored it some other way (like a public field or even in a WeakMap) and everything would have worked just as well.

We created a byLocation method that uses a normal JavaScript filter function to filter the array by location. And we use the somewhat obscure findIndex method to find the person we're updating, and updated the array by replacing the item at that index.

At this point, we have a very normal JavaScript library that completely hides the reactivity at its core.

If we then render the result of byLocation, the renderer will update the output whenever update is called.

The bottom line is: While Starbeam's reactive values and rendering concept may feel analogous to the reactive systems you're used to, the similarities end with those concepts. All other reads and writes to those reactive values are normal JavaScript.

Released under the MIT license