Intro to Reactivity

The reactivity system is extremely simple, but it can take some time to get to know it.

At a basic level, if you call use and pass in a property that belongs in a stateful context, it gives back a dynamic reference that will update automatically as the data updates.

The value of this inside a functional component is always stateful, letting this example from earlier work

function App() {
	this.counter = 0;
	return html`
		<div>
			<button on:click=${() => this.counter++}>Click me!</button>
			<p>${use(this.counter)}</p>
		</div>
	`;
}
function App() {
	this.counter = 0;
	return (
		<div>
			<button on:click={() => this.counter++}>Click me!</button>
			<p>{use(this.counter)}</p>
		</div>
	);
}
const App: Component<{},{
	counter: number
}> = function () {
	this.counter = 0;
	return (
		<div>
			<button on:click={() => this.counter++}>Click me!</button>
			<p>{use(this.counter)}</p>
		</div>
	);
}

In this example, whenever counter is updated, either from inside the component, from a parent component, or from devtools, the specific elements that depend on the value precisely update to reflect the new value with minimal overhead.

You can also manually create a stateful object, which is useful for nesting.

let state = $state({
	a: 0,
	b: $state({
		c: 1,
	}),
});

let elm = (
	<div>
		{" "}
		a is {use(state.a)}, c is {use(state.b.c)}
	</div>
);
document.body.appendChild(elm);

state.a++;
state.b.c++;
// div will now show "a is 1, c is 2"

Computed values

It’s important to remember that use yields a reference pointer, not the actual value. As such, something like this will not work

<div>
	<button on:click={() => this.counter++}>Click me!</button>
	{use(this.counter % 2 == 0 ? "Count Is Even" : "Count Is Odd")}
</div>

As the function is only executed once ever. To have additional logic tied to state changes, you can pass in a closure to the second argument of use.

<div>
	<button on:click={() => this.counter++}>Click me!</button>
	{use(this.counter, (count) => (count % 2 == 0 ? "Count Is Even" : "Count Is Odd"))}
</div>

This will have the expected behavior, flipping between even and odd when the button is pressed. Remember that the “count % 2 == 0” operation is recalculated every time count changes, but nothing else in the function is rerun.