mirror of https://github.com/sveltejs/svelte
parent
08612fab42
commit
54d76c97f1
@ -0,0 +1,87 @@
|
||||
---
|
||||
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;
|
||||
}
|
||||
```
|
||||
@ -1,87 +0,0 @@
|
||||
---
|
||||
title: $:
|
||||
---
|
||||
|
||||
Any top-level statement (i.e. not inside a block or a function) can be made reactive by prefixing it with the `$:` [JS label syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label). Reactive statements run after other script code and before the component markup is rendered, whenever the values that they depend on have changed.
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
export let title;
|
||||
export let person;
|
||||
|
||||
// this will update `document.title` whenever
|
||||
// the `title` prop changes
|
||||
$: document.title = title;
|
||||
|
||||
$: {
|
||||
console.log(`multiple statements can be combined`);
|
||||
console.log(`the current title is ${title}`);
|
||||
}
|
||||
|
||||
// this will update `name` when 'person' changes
|
||||
$: ({ name } = person);
|
||||
|
||||
// don't do this. it will run before the previous line
|
||||
let name2 = name;
|
||||
</script>
|
||||
```
|
||||
|
||||
Only values which directly appear within the `$:` block will become dependencies of the reactive statement. For example, in the code below `total` will only update when `x` changes, but not `y`.
|
||||
|
||||
```svelte
|
||||
<!--- file: App.svelte --->
|
||||
<script>
|
||||
let x = 0;
|
||||
let y = 0;
|
||||
|
||||
/** @param {number} value */
|
||||
function yPlusAValue(value) {
|
||||
return value + y;
|
||||
}
|
||||
|
||||
$: total = yPlusAValue(x);
|
||||
</script>
|
||||
|
||||
Total: {total}
|
||||
<button on:click={() => x++}> Increment X </button>
|
||||
|
||||
<button on:click={() => y++}> Increment Y </button>
|
||||
```
|
||||
|
||||
It is important to note that the reactive blocks are ordered via simple static analysis at compile time, and all the compiler looks at are the variables that are assigned to and used within the block itself, not in any functions called by them. This means that `yDependent` will not be updated when `x` is updated in the following example:
|
||||
|
||||
```svelte
|
||||
<!--- file: App.svelte --->
|
||||
<script>
|
||||
let x = 0;
|
||||
let y = 0;
|
||||
|
||||
/** @param {number} value */
|
||||
function setY(value) {
|
||||
y = value;
|
||||
}
|
||||
|
||||
$: yDependent = y;
|
||||
$: setY(x);
|
||||
</script>
|
||||
```
|
||||
|
||||
Moving the line `$: yDependent = y` below `$: setY(x)` will cause `yDependent` to be updated when `x` is updated.
|
||||
|
||||
If a statement consists entirely of an assignment to an undeclared variable, Svelte will inject a `let` declaration on your behalf.
|
||||
|
||||
```svelte
|
||||
<!--- file: App.svelte --->
|
||||
<script>
|
||||
/** @type {number} */
|
||||
export let num;
|
||||
|
||||
// we don't need to declare `squared` and `cubed`
|
||||
// — Svelte does it for us
|
||||
$: squared = num * num;
|
||||
$: cubed = squared * num;
|
||||
</script>
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> In Svelte 5+, reactions are handled via the [`$derived`]($derived) and [`$effect`]($effect) runes
|
||||
Loading…
Reference in new issue