Skip to content

Latest commit

 

History

History
121 lines (96 loc) · 2.87 KB

21-svelte-reactivity.md

File metadata and controls

121 lines (96 loc) · 2.87 KB
title
svelte/reactivity

Svelte provides reactive versions of various built-ins like SvelteMap, SvelteSet and SvelteURL. These can be imported from svelte/reactivity and used just like their native counterparts.

<script>
	import { SvelteURL } from 'svelte/reactivity';

	const url = new SvelteURL('https://example.com/path');
</script>

<!-- changes to these... -->
<input bind:value={url.protocol} />
<input bind:value={url.hostname} />
<input bind:value={url.pathname} />

<hr />

<!-- will update `href` and vice versa -->
<input bind:value={url.href} />

The utilities provided in svelte/reactivity are automatically reactive with respect to their properties and methods, as seen in the previous example. As such, they don't need to be wrapped in $state. However, if a variable is reassigned, it needs to be wrapped in a $state in order for this reassignement to be reactive.

<script>
	import { SvelteURL } from 'svelte/reactivity';

	let url = $state(new SvelteURL('https://example.com/path'));
</script>

<!-- these are reactive... -->
Protocol: {url?.protocol ?? "ftp:"}
<br>
Hostname: {url?.hostname ?? "svelte.dev"}
<br>
Path: {url?.pathname ?? ""}

<hr />

<!-- ...even when reassigning -->
<button
	onclick={() => {
		url = undefined;
	}}
>
	Erase
</button>

In a similar manner, the values stored inside e.g. SvelteMap are not automatically reactive, so if more complex values such as objects are used, they need to be wrapped in a $state in order to make their properties reactive as well. Alternatively, the whole object can be rewritten on update, which may actually lead to better performance than deep reactive $state.

<script>
	import { SvelteMap } from 'svelte/reactivity';

	const people = new SvelteMap();

	// A plain object
	const alice = {name: "Alice", age: 18};

	// A reactive object
	const bob = $state({name: "Bob", age: 21});

	people.set("alice", alice);
	people.set("bob", bob);
</script>

{#each people.entries() as [id, person] (id)}
	Name: {person.name}
	<br>
	Age: {person.age}
	<br>
	<br>
{/each}

<hr />

<!-- This will NOT propagate reactively, because alice is a plain object -->
<button
	onclick={() => {
		people.get("alice").age++;
	}}
>
	Alice's birthday
</button>

<!-- This WILL propagate reactively, because bob is a reactive object -->
<button
	onclick={() => {
		people.get("bob").age++;
	}}
>
	Bob's birthday
</button>

<!-- This WILL propagate reactively, because people is reactive -->
<button
	onclick={() => {
		people.set("carol", {name: "Carol", age: 0});
	}}
>
	Carol was born
</button>

{#if people.has("carol")}
	<!-- This WILL propagate reactively, because we are replacing the whole carol object -->
	<button
		onclick={() => {
			const oldValue = people.get("carol");
			people.set("carol", {...oldValue, age: oldValue.age + 1});
		}}
	>
		Carol's birthday
	</button>
{/if}

MODULE: svelte/reactivity