mirror of
https://github.com/sveltejs/svelte.git
synced 2024-12-01 09:21:21 +01:00
88 lines
2.4 KiB
Markdown
88 lines
2.4 KiB
Markdown
|
---
|
||
|
title: Reactive $: statements
|
||
|
---
|
||
|
|
||
|
In runes mode, reactions to state updates are handled with the [`$derived`]($derived) and [`$effect`]($effect) runes.
|
||
|
|
||
|
In legacy mode, any top-level statement (i.e. not inside a block or a function) can be made reactive by prefixing it with a `$:` [label](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label). These statements run after other code in the `<script>` and before the component markup is rendered, then whenever the values that they depend on change.
|
||
|
|
||
|
```svelte
|
||
|
<script>
|
||
|
let a = 1;
|
||
|
let b = 2;
|
||
|
|
||
|
// this is a 'reactive statement', and it will re-run
|
||
|
// when `a`, `b` or `sum` change
|
||
|
$: console.log(`${a} + ${b} = ${sum}`);
|
||
|
|
||
|
// this is a 'reactive assignment' — `sum` will be
|
||
|
// recalculated when `a` or `b` change. It is
|
||
|
// not necessary to declare `sum` separately
|
||
|
$: sum = a + b;
|
||
|
</script>
|
||
|
```
|
||
|
|
||
|
Statements are ordered _topologically_ by their dependencies and their assignments: since the `console.log` statement depends on `sum`, `sum` is calculated first even though it appears later in the source.
|
||
|
|
||
|
Multiple statements can be combined by putting them in a block:
|
||
|
|
||
|
```js
|
||
|
// @noErrors
|
||
|
$: {
|
||
|
// recalculate `total` when `items` changes
|
||
|
total = 0;
|
||
|
|
||
|
for (const item of items) {
|
||
|
total += item.value;
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
The left-hand side of a reactive assignments can be an identifier, or it can be a destructuring assignment:
|
||
|
|
||
|
```js
|
||
|
// @noErrors
|
||
|
$: ({ larry, moe, curly } = stooges);
|
||
|
```
|
||
|
|
||
|
## Understanding dependencies
|
||
|
|
||
|
The dependencies of a `$:` statement are determined at compile time — they are whichever variables are referenced (but not assigned to) inside the statement.
|
||
|
|
||
|
In other words, a statement like this will _not_ re-run when `count` changes, because the compiler cannot 'see' the dependency:
|
||
|
|
||
|
```js
|
||
|
// @noErrors
|
||
|
let count = 0;
|
||
|
let double = () => count * 2;
|
||
|
|
||
|
$: doubled = double();
|
||
|
```
|
||
|
|
||
|
Similarly, topological ordering will fail if dependencies are referenced indirectly: `z` will never update, because `y` is not considered 'dirty' when the update occurs. Moving `$: z = y` below `$: setY(x)` will fix it:
|
||
|
|
||
|
```svelte
|
||
|
<script>
|
||
|
let x = 0;
|
||
|
let y = 0;
|
||
|
|
||
|
$: z = y;
|
||
|
$: setY(x);
|
||
|
|
||
|
function setY(value) {
|
||
|
y = value;
|
||
|
}
|
||
|
</script>
|
||
|
```
|
||
|
|
||
|
## Browser-only code
|
||
|
|
||
|
Reactive statements run during server-side rendering as well as in the browser. This means that any code that should only run in the browser must be wrapped in an `if` block:
|
||
|
|
||
|
```js
|
||
|
// @noErrors
|
||
|
$: if (browser) {
|
||
|
document.title = title;
|
||
|
}
|
||
|
```
|