Skip to content

Commit 42bd7b8

Browse files
Sync svelte docs (#926)
sync svelte docs Co-authored-by: Rich-Harris <[email protected]>
1 parent 0d2d24f commit 42bd7b8

File tree

5 files changed

+283
-19
lines changed

5 files changed

+283
-19
lines changed

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

Lines changed: 135 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,7 @@ let todos = $state([
3636
...modifying an individual todo's property will trigger updates to anything in your UI that depends on that specific property:
3737

3838
```js
39-
// @filename: ambient.d.ts
40-
declare global {
41-
const todos: Array<{ done: boolean, text: string }>
42-
}
43-
44-
// @filename: index.js
39+
let todos = [{ done: false, text: 'add more todos' }];
4540
// ---cut---
4641
todos[0].done = !todos[0].done;
4742
```
@@ -64,6 +59,17 @@ todos.push({
6459

6560
> [!NOTE] When you update properties of proxies, the original object is _not_ mutated.
6661
62+
Note that if you destructure a reactive value, the references are not reactive — as in normal JavaScript, they are evaluated at the point of destructuring:
63+
64+
```js
65+
let todos = [{ done: false, text: 'add more todos' }];
66+
// ---cut---
67+
let { done, text } = todos[0];
68+
69+
// this will not affect the value of `done`
70+
todos[0].done = !todos[0].done;
71+
```
72+
6773
### Classes
6874

6975
You can also use `$state` in class fields (whether public or private):
@@ -85,7 +91,42 @@ class Todo {
8591
}
8692
```
8793

88-
> [!NOTE] The compiler transforms `done` and `text` into `get`/`set` methods on the class prototype referencing private fields.
94+
> [!NOTE] The compiler transforms `done` and `text` into `get`/`set` methods on the class prototype referencing private fields. This means the properties are not enumerable.
95+
96+
When calling methods in JavaScript, the value of [`this`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) matters. This won't work, because `this` inside the `reset` method will be the `<button>` rather than the `Todo`:
97+
98+
```svelte
99+
<button onclick={todo.reset}>
100+
reset
101+
</button>
102+
```
103+
104+
You can either use an inline function...
105+
106+
```svelte
107+
<button onclick=+++{() => todo.reset()}>+++
108+
reset
109+
</button>
110+
```
111+
112+
...or use an arrow function in the class definition:
113+
114+
```js
115+
// @errors: 7006 2554
116+
class Todo {
117+
done = $state(false);
118+
text = $state();
119+
120+
constructor(text) {
121+
this.text = text;
122+
}
123+
124+
+++reset = () => {+++
125+
this.text = '';
126+
this.done = false;
127+
}
128+
}
129+
```
89130

90131
## `$state.raw`
91132

@@ -127,3 +168,90 @@ To take a static snapshot of a deeply reactive `$state` proxy, use `$state.snaps
127168
```
128169

129170
This is handy when you want to pass some state to an external library or API that doesn't expect a proxy, such as `structuredClone`.
171+
172+
## Passing state into functions
173+
174+
JavaScript is a _pass-by-value_ language — when you call a function, the arguments are the _values_ rather than the _variables_. In other words:
175+
176+
```js
177+
/// file: index.js
178+
// @filename: index.js
179+
// ---cut---
180+
/**
181+
* @param {number} a
182+
* @param {number} b
183+
*/
184+
function add(a, b) {
185+
return a + b;
186+
}
187+
188+
let a = 1;
189+
let b = 2;
190+
let total = add(a, b);
191+
console.log(total); // 3
192+
193+
a = 3;
194+
b = 4;
195+
console.log(total); // still 3!
196+
```
197+
198+
If `add` wanted to have access to the _current_ values of `a` and `b`, and to return the current `total` value, you would need to use functions instead:
199+
200+
```js
201+
/// file: index.js
202+
// @filename: index.js
203+
// ---cut---
204+
/**
205+
* @param {() => number} getA
206+
* @param {() => number} getB
207+
*/
208+
function add(+++getA, getB+++) {
209+
return +++() => getA() + getB()+++;
210+
}
211+
212+
let a = 1;
213+
let b = 2;
214+
let total = add+++(() => a, () => b)+++;
215+
console.log(+++total()+++); // 3
216+
217+
a = 3;
218+
b = 4;
219+
console.log(+++total()+++); // 7
220+
```
221+
222+
State in Svelte is no different — when you reference something declared with the `$state` rune...
223+
224+
```js
225+
let a = +++$state(1)+++;
226+
let b = +++$state(2)+++;
227+
```
228+
229+
...you're accessing its _current value_.
230+
231+
Note that 'functions' is broad — it encompasses properties of proxies and [`get`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get)/[`set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set) properties...
232+
233+
```js
234+
/// file: index.js
235+
// @filename: index.js
236+
// ---cut---
237+
/**
238+
* @param {{ a: number, b: number }} input
239+
*/
240+
function add(input) {
241+
return {
242+
get value() {
243+
return input.a + input.b;
244+
}
245+
};
246+
}
247+
248+
let input = $state({ a: 1, b: 2 });
249+
let total = add(input);
250+
console.log(total.value); // 3
251+
252+
input.a = 3;
253+
input.b = 4;
254+
console.log(total.value); // 7
255+
```
256+
257+
...though if you find yourself writing code like that, consider using [classes](#Classes) instead.

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

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,39 @@
11
<!-- This file is generated by scripts/process-messages/index.js. Do not edit! -->
22

3+
### assignment_value_stale
4+
5+
```
6+
Assignment to `%property%` property (%location%) will evaluate to the right-hand side, not the value of `%property%` following the assignment. This may result in unexpected behaviour.
7+
```
8+
9+
Given a case like this...
10+
11+
```svelte
12+
<script>
13+
let object = $state({ array: null });
14+
15+
function add() {
16+
(object.array ??= []).push(object.array.length);
17+
}
18+
</script>
19+
20+
<button onclick={add}>add</button>
21+
<p>items: {JSON.stringify(object.items)}</p>
22+
```
23+
24+
...the array being pushed to when the button is first clicked is the `[]` on the right-hand side of the assignment, but the resulting value of `object.array` is an empty state proxy. As a result, the pushed value will be discarded.
25+
26+
You can fix this by separating it into two statements:
27+
28+
```js
29+
let object = { array: [0] };
30+
// ---cut---
31+
function add() {
32+
object.array ??= [];
33+
object.array.push(object.array.length);
34+
}
35+
```
36+
337
### binding_property_non_reactive
438
539
```
@@ -86,6 +120,46 @@ Mutating a value outside the component that created it is strongly discouraged.
86120
%component% mutated a value owned by %owner%. This is strongly discouraged. Consider passing values to child components with `bind:`, or use a callback instead
87121
```
88122

123+
### reactive_declaration_non_reactive_property
124+
125+
```
126+
A `$:` statement (%location%) read reactive state that was not visible to the compiler. Updates to this state will not cause the statement to re-run. The behaviour of this code will change if you migrate it to runes mode
127+
```
128+
129+
In legacy mode, a `$:` [reactive statement](https://svelte.dev/docs/svelte/legacy-reactive-assignments) re-runs when the state it _references_ changes. This is determined at compile time, by analysing the code.
130+
131+
In runes mode, effects and deriveds re-run when there are changes to the values that are read during the function's _execution_.
132+
133+
Often, the result is the same — for example these can be considered equivalent:
134+
135+
```js
136+
let a = 1, b = 2, sum = 3;
137+
// ---cut---
138+
$: sum = a + b;
139+
```
140+
141+
```js
142+
let a = 1, b = 2;
143+
// ---cut---
144+
const sum = $derived(a + b);
145+
```
146+
147+
In some cases — such as the one that triggered the above warning — they are _not_ the same:
148+
149+
```js
150+
let a = 1, b = 2, sum = 3;
151+
// ---cut---
152+
const add = () => a + b;
153+
154+
// the compiler can't 'see' that `sum` depends on `a` and `b`, but
155+
// they _would_ be read while executing the `$derived` version
156+
$: sum = add();
157+
```
158+
159+
Similarly, reactive properties of [deep state](https://svelte.dev/docs/svelte/$state#Deep-state) are not visible to the compiler. As such, changes to these properties will cause effects and deriveds to re-run but will _not_ cause `$:` statements to re-run.
160+
161+
When you [migrate this component](https://svelte.dev/docs/svelte/v5-migration-guide) to runes mode, the behaviour will change accordingly.
162+
89163
### state_proxy_equality_mismatch
90164

91165
```

apps/svelte.dev/content/docs/svelte/98-reference/.generated/compile-warnings.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -726,12 +726,6 @@ Reactive declarations only exist at the top level of the instance script
726726
Reassignments of module-level declarations will not cause reactive statements to update
727727
```
728728

729-
### reactive_declaration_non_reactive_property
730-
731-
```
732-
Properties of objects and arrays are not reactive unless in runes mode. Changes to this property will not cause the reactive statement to update
733-
```
734-
735729
### script_context_deprecated
736730

737731
```

apps/svelte.dev/content/docs/svelte/98-reference/30-compiler-warnings.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -746,12 +746,6 @@ Reactive declarations only exist at the top level of the instance script
746746
Reassignments of module-level declarations will not cause reactive statements to update
747747
```
748748

749-
### reactive_declaration_non_reactive_property
750-
751-
```
752-
Properties of objects and arrays are not reactive unless in runes mode. Changes to this property will not cause the reactive statement to update
753-
```
754-
755749
### script_context_deprecated
756750

757751
```

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

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,40 @@ title: 'Runtime warnings'
66

77
<!-- This file is generated by scripts/process-messages/index.js. Do not edit! -->
88

9+
### assignment_value_stale
10+
11+
```
12+
Assignment to `%property%` property (%location%) will evaluate to the right-hand side, not the value of `%property%` following the assignment. This may result in unexpected behaviour.
13+
```
14+
15+
Given a case like this...
16+
17+
```svelte
18+
<script>
19+
let object = $state({ array: null });
20+
21+
function add() {
22+
(object.array ??= []).push(object.array.length);
23+
}
24+
</script>
25+
26+
<button onclick={add}>add</button>
27+
<p>items: {JSON.stringify(object.items)}</p>
28+
```
29+
30+
...the array being pushed to when the button is first clicked is the `[]` on the right-hand side of the assignment, but the resulting value of `object.array` is an empty state proxy. As a result, the pushed value will be discarded.
31+
32+
You can fix this by separating it into two statements:
33+
34+
```js
35+
let object = { array: [0] };
36+
// ---cut---
37+
function add() {
38+
object.array ??= [];
39+
object.array.push(object.array.length);
40+
}
41+
```
42+
943
### binding_property_non_reactive
1044
1145
```
@@ -92,6 +126,46 @@ Mutating a value outside the component that created it is strongly discouraged.
92126
%component% mutated a value owned by %owner%. This is strongly discouraged. Consider passing values to child components with `bind:`, or use a callback instead
93127
```
94128

129+
### reactive_declaration_non_reactive_property
130+
131+
```
132+
A `$:` statement (%location%) read reactive state that was not visible to the compiler. Updates to this state will not cause the statement to re-run. The behaviour of this code will change if you migrate it to runes mode
133+
```
134+
135+
In legacy mode, a `$:` [reactive statement](https://svelte.dev/docs/svelte/legacy-reactive-assignments) re-runs when the state it _references_ changes. This is determined at compile time, by analysing the code.
136+
137+
In runes mode, effects and deriveds re-run when there are changes to the values that are read during the function's _execution_.
138+
139+
Often, the result is the same — for example these can be considered equivalent:
140+
141+
```js
142+
let a = 1, b = 2, sum = 3;
143+
// ---cut---
144+
$: sum = a + b;
145+
```
146+
147+
```js
148+
let a = 1, b = 2;
149+
// ---cut---
150+
const sum = $derived(a + b);
151+
```
152+
153+
In some cases — such as the one that triggered the above warning — they are _not_ the same:
154+
155+
```js
156+
let a = 1, b = 2, sum = 3;
157+
// ---cut---
158+
const add = () => a + b;
159+
160+
// the compiler can't 'see' that `sum` depends on `a` and `b`, but
161+
// they _would_ be read while executing the `$derived` version
162+
$: sum = add();
163+
```
164+
165+
Similarly, reactive properties of [deep state](https://svelte.dev/docs/svelte/$state#Deep-state) are not visible to the compiler. As such, changes to these properties will cause effects and deriveds to re-run but will _not_ cause `$:` statements to re-run.
166+
167+
When you [migrate this component](https://svelte.dev/docs/svelte/v5-migration-guide) to runes mode, the behaviour will change accordingly.
168+
95169
### state_proxy_equality_mismatch
96170

97171
```

0 commit comments

Comments
 (0)