Skip to content

Commit d33a616

Browse files
Rich-Harrisgithub-actions[bot]
authored andcommitted
sync svelte docs
1 parent 0d2d24f commit d33a616

File tree

1 file changed

+135
-7
lines changed

1 file changed

+135
-7
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+
a = 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.

0 commit comments

Comments
 (0)