Starbeam collections are reactive implementations of JavaScript built-in collections.
Starbeam collections behave identically to the JavaScript built-ins that they implement.
📢 Starbeam Collections do not support prototype mutation. This is the only known divergence from the JavaScript APIs.
Internally, Starbeam collections model JavaScript read operations in one of three ways:
- key accesses, which check whether a key is a member of the collection.
- value accesses, which access and return a value from the collection.
- key iterations, which iterate over a collection's keys.
- value iterations, which iterate over a collection's values.
For example, in the Map
API:
has(key)
is a key access.get(key)
is an value access.keys()
is a key iteration.values()
is a value iteration.entries()
is a key and value iteration.- iterating the map via
Symbol.iterator
orforEach
is a key and value iteration.
Consider this formula:
const recipes = reactive.Map(["pie", "http://example.com/pie-recipe"]);
const hasTastyFood = Formula(() => food.has("pie") || food.has("cookie"));
This formula makes two key accesses: "pie"
and "cookie"
.
If the URL for pie
is updated:
recipes.set("pie", "http://example.com/better-pie-recipe");
This formula updates the value of "pie"
, but the key has not changed. The
hasTastyFood
formula will not invalidate.
Categorizing operations this way supports the intuition that hasTastyFood
has
not changed by providing enough granularity to capture the user's intent.
If a formula iterates over a reactive collection, the formula will invalidate when the collection changes.
Replacing an existing value will invalidate a value iteration but not a key iteration. Adding a new entry or deleting an existing entry will invalidate both.
Let's create a couple of new formulas in our recipe example:
const recipeCount = Formula(() => recipes.size);
const uniqueRecipeURLs = Formula(
() => new Set([...recipes.values()].map((r) => r.url))
);
The recipeCount
formula only changes when the key iteration is invalidated.
So let's say we update the pie recipe again:
recipes.set("pie", "http://example.com/even-better-pie-recipe");
Since changing the value of an existing entry doesn't invalidate the key
iteration, the recipeCount
formula will not invalidate.
However, the uniqueRecipeURLs
formula will invalidate when the
collection changes.
Intuitively, this behaves just as we'd expect: changing the value of a recipe doesn't change the size of the recipes collection. But it might change the number of unique URLs.
Starbeam collections have predictable, granular invalidation rules. They cannot, however, avoid invalidating a formula just because the formula ultimately produces the same answer.
In this example, it's possible to invalidate uniqueRecipeURLs
by changing
the value of a recipe URL from a URL that has other existing entries to a URL
that also has existing entries.
In this situation, computing the formula will ultimately determine that nothing has changed. However, Starbeam invalidation rules are based upon the invalidation of storage cells, and never rely upon comparing the value of a previous computation with the value of a new computation.
In practice, this means that renderers may want to compare the new value to the old value in order to determine whether to do the work of updating the rendererd output.