Skip to content

Commit 4540ff3

Browse files
docs: tweak effect docs (#11982)
better examples --------- Co-authored-by: Simon H <[email protected]> Co-authored-by: Simon Holthausen <[email protected]>
1 parent ff94681 commit 4540ff3

File tree

1 file changed

+73
-22
lines changed
  • sites/svelte-5-preview/src/routes/docs/content/01-api

1 file changed

+73
-22
lines changed

sites/svelte-5-preview/src/routes/docs/content/01-api/02-runes.md

Lines changed: 73 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -335,49 +335,100 @@ In general, `$effect` is best considered something of an escape hatch — useful
335335

336336
> For things that are more complicated than a simple expression like `count * 2`, you can also use [`$derived.by`](#$derived-by).
337337
338-
When reacting to a state change and writing to a different state as a result, think about if it's possible to use callback props instead.
338+
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](/#H4sIAAAAAAAACpVRy2rDMBD8lWXJwYE0dg-9KFYg31H3oNirIJBlYa1DjPG_F8l1XEop9LgzOzP7mFAbSwHF-4ROtYQCL97jAXn0sQh3skx4wNANfR2RMtS98XyuXMWWGLhjZUHCa1GcVix4cgwSdoEVU1bsn4wl_Y1I2kS6inekNdWcZXuQZ5giFDWpfwl5WYyT2fynbB1g1UWbTVbm2w6utOpKNq1TGucHhri6rLBX7kYVwtW4RtyVHUhOyXeGVj3klLxnyJP0i8lXNJUx6en-v6A48K85kTimpi0sYj-yAo-Wlh9FcL1LY4K3ahSgLT1OC3ZTXkBxfKN2uVC6T5LjAduuMdpQg4L7geaP-RNHPuClMQIAAA==)):
339339

340340
```svelte
341-
<!-- Don't do this -->
342341
<script>
343-
let value = $state();
344-
let value_uppercase = $state();
342+
let total = 100;
343+
let spent = $state(0);
344+
let left = $state(total);
345+
346+
$effect(() => {
347+
left = total - spent;
348+
});
349+
345350
$effect(() => {
346-
value_uppercase = value.toUpperCase();
351+
spent = total - left;
347352
});
348353
</script>
349354
350-
<Text bind:value />
355+
<label>
356+
<input type="range" bind:value={spent} max={total} />
357+
{spent}/{total} spent
358+
</label>
351359
352-
<!-- Do this instead: -->
360+
<label>
361+
<input type="range" bind:value={left} max={total} />
362+
{left.value}/{total} left
363+
</label>
364+
```
365+
366+
Instead, use callbacks where possible ([demo](/#H4sIAAAAAAAACo2SP2-DMBDFv8rp1CFR84cOXQhU6p6tY-ngwoEsGWPhI0pk8d0rG5yglqGj37v7veMJh7VUZDH9dKhFS5jiuzG4Q74Z_7AXUky4Q9sNfemVzJa9NPxW6IIVMXDHQkEOL0lyipo1pBlyeLIsmDbJ9u4oqhdG2A2mLrgedMmy0zCYSjB9eMaGtuC8WXBkPtOBRd8QHy5CDXSa3Jk7HbOfDgjWuAo_U71kz9vr6Bgc2X44orPjow2dKfFNKhSTSW0GBl9iXmAvdEMFQqDmLgBH6HQYyt3ie0doxTV3IWqEY2DN88eohqePvsf9O9mf_if4HMSVXD89NfEI99qvbMs3RdPv4MXYaSWtUeKWQq3oOlfZCJNCcnildlFgWMcdtl0la0kVptwPNH6NP_uzV0acAgAA)):
367+
368+
```svelte
353369
<script>
354-
let value = $state();
355-
let value_uppercase = $state();
356-
function onValueChange(new_text) {
357-
value = new_text;
358-
value_uppercase = new_text.toUpperCase();
370+
let total = 100;
371+
let spent = $state(0);
372+
let left = $state(total);
373+
374+
function updateSpent(e) {
375+
spent = +e.target.value;
376+
left = total - spent;
359377
}
360-
</script>
361378
362-
<Text {value} {onValueChange}>
363-
```
379+
function updateLeft(e) {
380+
left = +e.target.value;
381+
spent = total - left;
382+
}
383+
</script>
364384
365-
If you want to have something update from above but also modify it from below (i.e. you want some kind of "writable `$derived`"), and events aren't an option, you can also use an object with getters and setters.
385+
<label>
386+
<input
387+
type="range"
388+
value={spent}
389+
oninput={updateSpent}
390+
max={total}
391+
/>
392+
{spent}/{total} spent
393+
</label>
394+
395+
<label>
396+
<input
397+
type="range"
398+
value={left}
399+
oninput={updateLeft}
400+
max={total}
401+
/>
402+
{left}/{total} left
403+
</label>
404+
```
405+
406+
If you need to use bindings, for whatever reason (for example when you want some kind of "writable `$derived`"), consider using getters and setters to synchronise state ([demo](/#H4sIAAAAAAAACo2SQW-DMAyF_4pl7dBqXcsOu1CYtHtvO44dsmKqSCFExFRFiP8-xRCGth52tJ_9PecpA1bakMf0Y0CrasIU35zDHXLvQuGvZJhwh77p2nPoZP7casevhS3YEAM3rAzk8Jwkx9jzjixDDg-eFdMm2S6KoWolyK6ItuCqs2fWjYXOlYrpPTA2tIUhiAVH5iPtWbUX4v1VmY6Okzpzp2OepgNEGu_CT1St2fP2fXQ0juwwHNHZ4ScNmxn1RUaCybR1HUMIMS-wVfZCBYJQ80GAIzRWhvJh9d4RanXLB7Ea4SCsef4Qu1IG68Xu387h9D_GJ2ne8ZXpxTZUv1w994amjxCaMc1Se2dUn0Jl6DaHeFEuhWT_QvUqOlnHHdZNqStNJabcdjR-jt8IbC-7lgIAAA==)):
366407

367408
```svelte
368409
<script>
369-
let { value } = $props();
370-
let facade = {
410+
let total = 100;
411+
let spent = $state(0);
412+
413+
let left = {
371414
get value() {
372-
return value.toUpperCase();
415+
return total - spent;
373416
},
374-
set value(val) {
375-
value = val.toLowerCase();
417+
set value(v) {
418+
spent = total - v;
376419
}
377420
};
378421
</script>
379422
380-
<input bind:value={facade.value} />
423+
<label>
424+
<input type="range" bind:value={spent} max={total} />
425+
{spent}/{total} spent
426+
</label>
427+
428+
<label>
429+
<input type="range" bind:value={left.value} max={total} />
430+
{left.value}/{total} left
431+
</label>
381432
```
382433

383434
If you absolutely have to update `$state` within an effect and run into an infinite loop because you read and write to the same `$state`, use [untrack](functions#untrack).

0 commit comments

Comments
 (0)