Skip to content

What Can Become Reactive?

In Starbeam, reactive reads and writes look equivalent to non-reactive reads and writes.

This means that JavaScript syntax that looks dynamic (such as property access and method calls) can become reactive, while JavaScript syntax that does not look dynamic (such as reading and writing from let variables) is not reactive.

Can Become ReactiveCan Not Become Reactive
Accessing a property (. or [])Accessing a let variable
Accessing an import (import { x })
Iterating an object's own keysIterating a module's exports
Checking a property's presence (in)Checking a private field's presence (#x in this)
Calling a function or methodCalling an undecorated private method
Accessing a decorated private fieldAccessing an undecorated private field

In practice, this means that the entire external API of a JavaScript object can become reactive.

Reactive Builtins

Building on this approach, Starbeam provides reactive versions of many JavaScript builtin collections:

Reactive Types

  • object
  • array
  • Map
  • Set
  • Array
  • WeakMap
  • WeakSet

Here's an example using a reactive Map. The key point is that you use a reactive Map in precisely the same way you would use a non-reactive Map.

tsx
tsx
import * as reactive from "@starbeam/collections";
 
const people = reactive.Map<string, Person>();
 
// This is a placeholder for an actual React renderer.
render(() => {
return (
<>
{[...people].map(([id, person]) => {
return (
<div key={id}>
{person.name} ({person.affiliation})
</div>
);
})}
</>
);
});
 
people.set("1", {
name: "nullvox",
affiliation: "Auditboard",
});
 
interface Person {
name: string;
affiliation: string;
}
tsx
import * as reactive from "@starbeam/collections";
 
const people = reactive.Map<string, Person>();
 
// This is a placeholder for an actual React renderer.
render(() => {
return (
<>
{[...people].map(([id, person]) => {
return (
<div key={id}>
{person.name} ({person.affiliation})
</div>
);
})}
</>
);
});
 
people.set("1", {
name: "nullvox",
affiliation: "Auditboard",
});
 
interface Person {
name: string;
affiliation: string;
}

This example uses [...spread] and normal JavaScript map to render the Map.

JSX Syntax Is Just An Example

This example uses JSX syntax as an illustration of how you would render a reactive object. In practice, you would use the Starbeam renderer for your framework, and the same principles would apply.

And the same goes for updates. You update a reactive Map using its normal APIs.

tsx
tsx
import * as reactive from "@starbeam/collections";
 
const people = reactive.Map<string, Person>();
 
// This is a placeholder for an actual React renderer.
render(() => {
return (
<>
{[...people].map(([id, person]) => {
return (
<div key={id}>
{person.name} ({person.affiliation})
</div>
);
})}
</>
);
});
 
people.set("1", {
name: "nullvox",
affiliation: "Auditboard",
});
 
interface Person {
name: string;
affiliation: string;
}
tsx
import * as reactive from "@starbeam/collections";
 
const people = reactive.Map<string, Person>();
 
// This is a placeholder for an actual React renderer.
render(() => {
return (
<>
{[...people].map(([id, person]) => {
return (
<div key={id}>
{person.name} ({person.affiliation})
</div>
);
})}
</>
);
});
 
people.set("1", {
name: "nullvox",
affiliation: "Auditboard",
});
 
interface Person {
name: string;
affiliation: string;
}