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.