Skip to content

Commit 967ccc5

Browse files
committed
add warning in dev, add docs
1 parent 6104205 commit 967ccc5

File tree

7 files changed

+57
-12
lines changed

7 files changed

+57
-12
lines changed

documentation/docs/02-runes/02-$state.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,19 @@ let { done, text } = todos[0];
6565
todos[0].done = !todos[0].done;
6666
```
6767

68+
You can also use `$state` in return statements to proxy their argument:
69+
70+
```js
71+
function createCounter() {
72+
return $state({
73+
count: 0,
74+
increment() {
75+
this.count++;
76+
}
77+
});
78+
}
79+
```
80+
6881
### Classes
6982

7083
You can also use `$state` in class fields (whether public or private):

documentation/docs/98-reference/.generated/client-warnings.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,12 @@ Reactive `$state(...)` proxies and the values they proxy have different identiti
219219
220220
To resolve this, ensure you're comparing values where both values were created with `$state(...)`, or neither were. Note that `$state.raw(...)` will _not_ create a state proxy.
221221
222+
### state_return_not_proxyable
223+
224+
```
225+
The argument passed to a `$state` in a return statement must be a plain object or array. Otherwise, the `$state` call will have no effect
226+
```
227+
222228
### transition_slide_display
223229
224230
```

packages/svelte/messages/client-warnings/warnings.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,10 @@ To fix it, either create callback props to communicate changes, or mark `person`
185185
186186
To resolve this, ensure you're comparing values where both values were created with `$state(...)`, or neither were. Note that `$state.raw(...)` will _not_ create a state proxy.
187187
188+
## state_return_not_proxyable
189+
190+
> The argument passed to a `$state` call in a return statement must be a plain object or array. Otherwise, the `$state` call will have no effect
191+
188192
## transition_slide_display
189193
190194
> The `slide` transition does not work correctly for elements with `display: %value%`

packages/svelte/src/compiler/phases/3-transform/client/visitors/CallExpression.js

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,11 @@ export function CallExpression(node, context) {
4040
parent?.type === 'ReturnStatement' ||
4141
(parent?.type === 'ArrowFunctionExpression' && parent.body === node)
4242
) {
43-
if (
44-
node.arguments[0] &&
45-
should_proxy(
46-
/** @type {Expression} */ (context.visit(node.arguments[0])),
47-
context.state.scope
48-
)
49-
) {
50-
return b.call('$.proxy', node.arguments[0]);
51-
} else {
52-
return node.arguments[0] ?? b.void0;
43+
if (node.arguments[0]) {
44+
return b.call(
45+
'$.return_proxy',
46+
/** @type {Expression} */ (context.visit(node.arguments[0] ?? b.void0))
47+
);
5348
}
5449
}
5550
}

packages/svelte/src/internal/client/proxy.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { state as source, set } from './reactivity/sources.js';
1212
import { STATE_SYMBOL } from '#client/constants';
1313
import { UNINITIALIZED } from '../../constants.js';
1414
import * as e from './errors.js';
15+
import * as w from './warnings.js';
1516
import { get_stack } from './dev/tracing.js';
1617
import { tracing_mode_flag } from '../flags/index.js';
1718

@@ -282,6 +283,21 @@ export function proxy(value) {
282283
});
283284
}
284285

286+
/**
287+
* @template T
288+
* @param {T} value
289+
* @param {Source<T>} [prev]
290+
* @returns {T | void}
291+
*/
292+
export function return_proxy(value, prev) {
293+
const res = proxy(value, prev);
294+
if (res !== value || (typeof value === 'object' && value !== null && STATE_SYMBOL in value)) {
295+
// if the argument passed was already a proxy, we don't warn
296+
return res;
297+
}
298+
w.state_return_not_proxyable();
299+
}
300+
285301
/**
286302
* @param {Source<number>} signal
287303
* @param {1 | -1} [d]

packages/svelte/src/internal/client/warnings.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,17 @@ export function state_proxy_equality_mismatch(operator) {
170170
}
171171
}
172172

173+
/**
174+
* The argument passed to a `$state` in a return statement must be a plain object or array. Otherwise, the `$state` call will have no effect
175+
*/
176+
export function state_return_not_proxyable() {
177+
if (DEV) {
178+
console.warn(`%c[svelte] state_return_not_proxyable\n%cThe argument passed to a \`$state\` in a return statement must be a plain object or array. Otherwise, the \`$state\` call will have no effect\nhttps://svelte.dev/e/state_return_not_proxyable`, bold, normal);
179+
} else {
180+
console.warn(`https://svelte.dev/e/state_return_not_proxyable`);
181+
}
182+
}
183+
173184
/**
174185
* The `slide` transition does not work correctly for elements with `display: %value%`
175186
* @param {string} value

packages/svelte/tests/snapshot/samples/state-in-return/_expected/client/index.svelte.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import * as $ from 'svelte/internal/client';
33

44
export default function proxy(object) {
5-
return $.proxy(object);
5+
return $.return_proxy(object);
66
}
77

88
export function createCounter() {
@@ -11,4 +11,4 @@ export function createCounter() {
1111
$.update(count);
1212
}
1313

14-
export const proxy_in_arrow = (object) => $.proxy(object);
14+
export const proxy_in_arrow = (object) => $.return_proxy(object);

0 commit comments

Comments
 (0)