Skip to content

Commit f9e3f20

Browse files
Sync svelte docs (#1209)
sync svelte docs Co-authored-by: svelte-docs-bot[bot] <196124396+svelte-docs-bot[bot]@users.noreply.github.com>
1 parent 21d6ef8 commit f9e3f20

File tree

4 files changed

+88
-30
lines changed

4 files changed

+88
-30
lines changed

apps/svelte.dev/content/docs/svelte/02-runes/03-$derived.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,48 @@ Anything read synchronously inside the `$derived` expression (or `$derived.by` f
5353

5454
To exempt a piece of state from being treated as a dependency, use [`untrack`](svelte#untrack).
5555

56+
## Overriding derived values
57+
58+
Derived expressions are recalculated when their dependencies change, but you can temporarily override their values by reassigning them (unless they are declared with `const`). This can be useful for things like _optimistic UI_, where a value is derived from the 'source of truth' (such as data from your server) but you'd like to show immediate feedback to the user:
59+
60+
```svelte
61+
<script>
62+
let { post, like } = $props();
63+
64+
let likes = $derived(post.likes);
65+
66+
async function onclick() {
67+
// increment the `likes` count immediately...
68+
likes += 1;
69+
70+
// and tell the server, which will eventually update `post`
71+
try {
72+
await like();
73+
} catch {
74+
// failed! roll back the change
75+
likes -= 1;
76+
}
77+
}
78+
</script>
79+
80+
<button {onclick}>🧡 {likes}</button>
81+
```
82+
83+
> [!NOTE] Prior to Svelte 5.25, deriveds were read-only.
84+
85+
## Deriveds and reactivity
86+
87+
Unlike `$state`, which converts objects and arrays to [deeply reactive proxies]($state#Deep-state), `$derived` values are left as-is. For example, [in a case like this](/playground/untitled#H4sIAAAAAAAAE4VU22rjMBD9lUHd3aaQi9PdstS1A3t5XvpQ2Ic4D7I1iUUV2UjjNMX431eS7TRdSosxgjMzZ45mjt0yzffIYibvy0ojFJWqDKCQVBk2ZVup0LJ43TJ6rn2aBxw-FP2o67k9oCKP5dziW3hRaUJNjoYltjCyplWmM1JIIAn3FlL4ZIkTTtYez6jtj4w8WwyXv9GiIXiQxLVs9pfTMR7EuoSLIuLFbX7Z4930bZo_nBrD1bs834tlfvsBz9_SyX6PZXu9XaL4gOWn4sXjeyzftv4ZWfyxubpzxzg6LfD4MrooxELEosKCUPigQCMPKCZh0OtQE1iSxcsmdHuBvCiHZXALLXiN08EL3RRkaJ_kDVGle0HcSD5TPEeVtj67O4Nrg9aiSNtBY5oODJkrL5QsHtN2cgXp6nSJMWzpWWGasdlsGEMbzi5jPr5KFr0Ep7pdeM2-TCelCddIhDxAobi1jqF3cMaC1RKp64bAW9iFAmXGIHfd4wNXDabtOLN53w8W53VvJoZLh7xk4Rr3CoL-UNoLhWHrT1JQGcM17u96oES5K-kc2XOzkzqGCKL5De79OUTyyrg1zgwXsrEx3ESfx4Bz0M5UjVMHB24mw9SuXtXFoN13fYKOM1tyUT3FbvbWmSWCZX2Er-41u5xPoml45svRahl9Wb9aasbINJixDZwcPTbyTLZSUsAvrg_cPuCR7s782_WU8343Y72Qtlb8OYatwuOQvuN13M_hJKNfxann1v1U_B1KZ_D_mzhzhz24fw85CSz2irtN9w9HshBK7AQAAA==)...
88+
89+
```svelte
90+
let items = $state([...]);
91+
92+
let index = $state(0);
93+
let selected = $derived(items[index]);
94+
```
95+
96+
...you can change (or `bind:` to) properties of `selected` and it will affect the underlying `items` array. If `items` was _not_ deeply reactive, mutating `selected` would have no effect.
97+
5698
## Update propagation
5799

58100
Svelte uses something called _push-pull reactivity_ — when state is updated, everything that depends on the state (whether directly or indirectly) is immediately notified of the change (the 'push'), but derived values are not re-evaluated until they are actually read (the 'pull').

apps/svelte.dev/content/docs/svelte/02-runes/04-$effect.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,8 @@ In general, `$effect` is best considered something of an escape hatch — useful
255255

256256
> [!NOTE] For things that are more complicated than a simple expression like `count * 2`, you can also use `$derived.by`.
257257
258+
If you're using an effect because you want to be able to reassign the derived value (to build an optimistic UI, for example) note that [deriveds can be directly overridden]($derived#Overriding-derived-values) as of Svelte 5.25.
259+
258260
You might be tempted to do something convoluted with effects to link one value to another. The following example shows two inputs for "money spent" and "money left" that are connected to each other. If you update one, the other should update accordingly. Don't use effects for this ([demo](/playground/untitled#H4sIAAAAAAAACpVRy26DMBD8FcvKgUhtoIdeHBwp31F6MGSJkBbHwksEQvx77aWQqooq9bgzOzP7mGTdIHipPiZJowOpGJAv0po2VmfnDv4OSBErjYdneHWzBJaCjcx91TWOToUtCIEE3cig0OIty44r5l1oDtjOkyFIsv3GINQ_CNYyGegd1DVUlCR7oU9iilDUcP8S8roYs9n8p2wdYNVFm4csTx872BxNCcjr5I11fdgonEkXsjP2CoUUZWMv6m6wBz2x7yxaM-iJvWeRsvSbSVeUy5i0uf8vKA78NIeJLSZWv1I8jQjLdyK4XuTSeIdmVKJGGI4LdjVOiezwDu1yG74My8PLCQaSiroe5s_5C2PHrkVGAgAA)):
259261

260262
```svelte

apps/svelte.dev/content/docs/svelte/98-reference/.generated/client-errors.md

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -128,26 +128,33 @@ Cannot set prototype of `$state` object
128128
Updating state inside a derived or a template expression is forbidden. If the value should not be reactive, declare it without `$state`
129129
```
130130

131-
This error is thrown in a situation like this:
131+
This error occurs when state is updated while evaluating a `$derived`. You might encounter it while trying to 'derive' two pieces of state in one go:
132132

133133
```svelte
134134
<script>
135-
let count = $state(0);
136-
let multiple = $derived.by(() => {
137-
const result = count * 2;
138-
if (result > 10) {
139-
count = 0;
140-
}
141-
return result;
142-
});
135+
let count = $state(0);
136+
137+
let even = $state(true);
138+
139+
let odd = $derived.by(() => {
140+
even = count % 2 === 0;
141+
return !even;
142+
});
143143
</script>
144144
145-
<button onclick={() => count++}>{count} / {multiple}</button>
145+
<button onclick={() => count++}>{count}</button>
146+
147+
<p>{count} is even: {even}</p>
148+
<p>{count} is odd: {odd}</p>
146149
```
147150

148-
Here, the `$derived` updates `count`, which is `$state` and therefore forbidden to do. It is forbidden because the reactive graph could become unstable as a result, leading to subtle bugs, like values being stale or effects firing in the wrong order. To prevent this, Svelte errors when detecting an update to a `$state` variable.
151+
This is forbidden because it introduces instability: if `<p>{count} is even: {even}</p>` is updated before `odd` is recalculated, `even` will be stale. In most cases the solution is to make everything derived:
152+
153+
```js
154+
let count = 0;
155+
// ---cut---
156+
let even = $derived(count % 2 === 0);
157+
let odd = $derived(!even);
158+
```
149159

150-
To fix this:
151-
- See if it's possible to refactor your `$derived` such that the update becomes unnecessary
152-
- Think about why you need to update `$state` inside a `$derived` in the first place. Maybe it's because you're using `bind:`, which leads you down a bad code path, and separating input and output path (by splitting it up to an attribute and an event, or by using [Function bindings](bind#Function-bindings)) makes it possible avoid the update
153-
- If it's unavoidable, you may need to use an [`$effect`]($effect) instead. This could include splitting parts of the `$derived` into an [`$effect`]($effect) which does the updates
160+
If side-effects are unavoidable, use [`$effect`]($effect) instead.

apps/svelte.dev/content/docs/svelte/98-reference/30-runtime-errors.md

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -135,29 +135,36 @@ Cannot set prototype of `$state` object
135135
Updating state inside a derived or a template expression is forbidden. If the value should not be reactive, declare it without `$state`
136136
```
137137

138-
This error is thrown in a situation like this:
138+
This error occurs when state is updated while evaluating a `$derived`. You might encounter it while trying to 'derive' two pieces of state in one go:
139139

140140
```svelte
141141
<script>
142-
let count = $state(0);
143-
let multiple = $derived.by(() => {
144-
const result = count * 2;
145-
if (result > 10) {
146-
count = 0;
147-
}
148-
return result;
149-
});
142+
let count = $state(0);
143+
144+
let even = $state(true);
145+
146+
let odd = $derived.by(() => {
147+
even = count % 2 === 0;
148+
return !even;
149+
});
150150
</script>
151151
152-
<button onclick={() => count++}>{count} / {multiple}</button>
152+
<button onclick={() => count++}>{count}</button>
153+
154+
<p>{count} is even: {even}</p>
155+
<p>{count} is odd: {odd}</p>
153156
```
154157

155-
Here, the `$derived` updates `count`, which is `$state` and therefore forbidden to do. It is forbidden because the reactive graph could become unstable as a result, leading to subtle bugs, like values being stale or effects firing in the wrong order. To prevent this, Svelte errors when detecting an update to a `$state` variable.
158+
This is forbidden because it introduces instability: if `<p>{count} is even: {even}</p>` is updated before `odd` is recalculated, `even` will be stale. In most cases the solution is to make everything derived:
159+
160+
```js
161+
let count = 0;
162+
// ---cut---
163+
let even = $derived(count % 2 === 0);
164+
let odd = $derived(!even);
165+
```
156166

157-
To fix this:
158-
- See if it's possible to refactor your `$derived` such that the update becomes unnecessary
159-
- Think about why you need to update `$state` inside a `$derived` in the first place. Maybe it's because you're using `bind:`, which leads you down a bad code path, and separating input and output path (by splitting it up to an attribute and an event, or by using [Function bindings](bind#Function-bindings)) makes it possible avoid the update
160-
- If it's unavoidable, you may need to use an [`$effect`]($effect) instead. This could include splitting parts of the `$derived` into an [`$effect`]($effect) which does the updates
167+
If side-effects are unavoidable, use [`$effect`]($effect) instead.
161168

162169

163170
## Server errors

0 commit comments

Comments
 (0)