Reactive Rendering
Once you've created a reactive object or resource using Starbeam, you can use it in your application using the appropriate Starbeam renderer for your web framework.
Universal Reactivity
Starbeam's universal APIs allow you to create reactive objects and synchronize external state in a way that can be shared across web frameworks. We call these "universal reactive objects".
Framework renderers provide APIs for using universal reactive objects in different web frameworks.
To render something using Starbeam, we first need a reactive object. We'll use a reactive todo list as an example.
- First, we'll build the reactive todo list using Starbeam's reactive APIs, and without any reference to any specific web framework.
- Then, we'll see how to use Starbeam renderers to create a todo list UI that will remain up-to-date when the todo list changes.to thyou
The Universal Reactive Object
Consider these reactive class that represent (a) a list of todo items, (b) a todo item:
ts
import * asreactive from "@starbeam/collections";export classTodoItems {readonly #items =reactive .Map <string,TodoItem >();add (title : string):TodoItem {consttodo = newTodoItem (title );this.#items.set (todo .id ,todo );returntodo ;}toggleAll (checked : boolean): void {for (constitem of this.#items.values ()) {item .toggle (checked );}}clearCompleted (): void {for (constitem of this.#items.values ()) {if (item .completed ) {this.#items.delete (item .id );}}}filter (filter : (item :TodoItem ) => boolean):TodoItem [] {return [...this.#items.values ()].filter (filter );}remove (id : string): void {this.#items.delete (id );}}classTodoItem {readonlyid =crypto .randomUUID ();@tracked accessorcompleted = false;@tracked accessortitle : string;constructor(title : string) {this.title =title ;}toggle (checked = !this.completed ): void {this.completed =checked ;}}
ts
import * asreactive from "@starbeam/collections";export classTodoItems {readonly #items =reactive .Map <string,TodoItem >();add (title : string):TodoItem {consttodo = newTodoItem (title );this.#items.set (todo .id ,todo );returntodo ;}toggleAll (checked : boolean): void {for (constitem of this.#items.values ()) {item .toggle (checked );}}clearCompleted (): void {for (constitem of this.#items.values ()) {if (item .completed ) {this.#items.delete (item .id );}}}filter (filter : (item :TodoItem ) => boolean):TodoItem [] {return [...this.#items.values ()].filter (filter );}remove (id : string): void {this.#items.delete (id );}}classTodoItem {readonlyid =crypto .randomUUID ();@tracked accessorcompleted = false;@tracked accessortitle : string;constructor(title : string) {this.title =title ;}toggle (checked = !this.completed ): void {this.completed =checked ;}}
We wrote this reactive todo list using Starbeam's reactive APIs.
Rendering
What we mean when we say that the todo list is "reactive" is that we can create an output UI that is up-to-date with the current state of the todo list.
Starbeam renderers allow you to do just that: take a reactive object and use your framework of choice to render a UI that will remain up-to-date when the reactive object changes.
class TodoList extends Component {
readonly #todos = new TodoItems();
@tracked #filter = (todo: TodoItem) => true;
createTodo = (e: FormEvent) => {
e.preventDefault();
const text = e.target["text"].value;
this.#todos.add(text);
e.target["text"].value = "";
};
<template>
<header>
<h1>Todos</h1>
<form {{on "submit" (this.createTodo)}}>
<input
type="text"
name="text"
placeholder="What needs to be done?"
>
<button type="submit">Create</button>
</form>
</header>
<section class="main">
<ul class="todo-list">
{{#each (this.#todos.filter this.filter) as |todo|}}
<TodoItem @todo={{todo}} @todos={{this.#todos}} />
{{/each}}
</ul>
</section>
</template>
}
const TodoItem = <template>
<li>
<input
type="checkbox" checked={{@todo.completed}}
{{on "input" (@todo.completed)}}
>
<p>{{@todo.text}}</p>
<button {{on "click" (@todos.remove todo)}}>
x
</button>
</li>
</template>