0
0
mirror of https://github.com/sveltejs/svelte.git synced 2024-11-28 16:12:17 +01:00
svelte/documentation/docs/01-introduction/xx-reactivity-fundamentals.md
2024-10-22 21:08:01 +02:00

4.3 KiB

title
Reactivity fundamentals

Reactivity is at the heart of interactive UIs. When you click a button, you expect some kind of response. It's your job as a developer to make this happen. It's Svelte's job to make your job as intuitive as possible, by providing a good API to express reactive systems.

Runes

Svelte 5 uses runes, a powerful set of primitives for controlling reactivity inside your Svelte components and inside .svelte.js and .svelte.ts modules.

Runes are function-like symbols that provide instructions to the Svelte compiler. You don't need to import them from anywhere — when you use Svelte, they're part of the language.

The following sections introduce the most important runes for declare state, derived state and side effects at a high level. For more details refer to the later sections on state and side effects.

$state

Reactive state is declared with the $state rune:

<script>
	let count = $state(0);
</script>

<button onclick={() => count++}>
	clicks: {count}
</button>

You can also use $state in class fields (whether public or private):

// @errors: 7006 2554
class Todo {
	done = $state(false);
	text = $state();

	constructor(text) {
		this.text = text;
	}
}

[!LEGACY] In Svelte 4, state was implicitly reactive if the variable was declared at the top level

<script>
	let count = 0;
</script>

<button on:click={() => count++}>
	clicks: {count}
</button>

$derived

Derived state is declared with the $derived rune:

<script>
	let count = $state(0);
	let doubled = $derived(count * 2);
</script>

<button onclick={() => count++}>
	{doubled}
</button>

<p>{count} doubled is {doubled}</p>

The expression inside $derived(...) should be free of side-effects. Svelte will disallow state changes (e.g. count++) inside derived expressions.

As with $state, you can mark class fields as $derived.

[!LEGACY] In Svelte 4, you could use reactive statements for this.

<script>
	let count = 0;
	$: doubled = count * 2;
</script>

<button on:click={() => count++}>
	{doubled}
</button>

<p>{count} doubled is {doubled}</p>

This only worked at the top level of a component.

$effect

To run side-effects when the component is mounted to the DOM, and when values change, we can use the $effect rune (demo):

<script>
	let size = $state(50);
	let color = $state('#ff3e00');

	let canvas;

	$effect(() => {
		const context = canvas.getContext('2d');
		context.clearRect(0, 0, canvas.width, canvas.height);

		// this will re-run whenever `color` or `size` change
		context.fillStyle = color;
		context.fillRect(0, 0, size, size);
	});
</script>

<canvas bind:this={canvas} width="100" height="100" />

The function passed to $effect will run when the component mounts, and will re-run after any changes to the values it reads that were declared with $state or $derived (including those passed in with $props). Re-runs are batched (i.e. changing color and size in the same moment won't cause two separate runs), and happen after any DOM updates have been applied.

[!LEGACY] In Svelte 4, you could use reactive statements for this.

<script>
	let size = 50;
	let color = '#ff3e00';

	let canvas;

	$: {
		const context = canvas.getContext('2d');
		context.clearRect(0, 0, canvas.width, canvas.height);

		// this will re-run whenever `color` or `size` change
		context.fillStyle = color;
		context.fillRect(0, 0, size, size);
	}
</script>

<canvas bind:this={canvas} width="100" height="100" />

This only worked at the top level of a component.