Skip to content

Commit 3515776

Browse files
authored
docs: tweak $state.is warning (#12599)
Also add a detailed explanation which can later appear on the docs site closes #11556
1 parent afa3128 commit 3515776

File tree

4 files changed

+40
-10
lines changed

4 files changed

+40
-10
lines changed

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,24 @@
4040
4141
## state_proxy_equality_mismatch
4242

43-
> Reactive `$state(...)` proxies and the values they proxy have different identities. Because of this, comparisons with `%operator%` will produce unexpected results. Consider using `$state.is(a, b)` instead
43+
> Reactive `$state(...)` proxies and the values they proxy have different identities. Because of this, comparisons with `%operator%` will produce unexpected results. Consider using `$state.is(a, b)` instead%details%
44+
45+
`$state(...)` does create a proxy of the value it is passed. Therefore, the resulting object has a different identity and equality checks will always return `false`:
46+
47+
```svelte
48+
<script>
49+
let object = { foo: 'bar' };
50+
let state_object = $state(object);
51+
object === state_object; // always false
52+
</script>
53+
```
54+
55+
Most of the time this will not be a problem in practise because it is very rare to keep the original value around to later compare it against a state value. In case it happens, Svelte will warn you about it in development mode and suggest to use `$state.is` instead, which is able to unwrap the proxy and compare the original values:
56+
57+
```svelte
58+
<script>
59+
let object = { foo: 'bar' };
60+
let state_object = $state(object);
61+
$state.is(object, state_object); // true
62+
</script>
63+
```

packages/svelte/scripts/process-messages/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ for (const category of fs.readdirSync('messages')) {
3333

3434
const sections = text.trim().split('\n\n');
3535
let details = null;
36-
if (!sections[sections.length - 1].startsWith('> ')) {
36+
while (!sections[sections.length - 1].startsWith('> ')) {
3737
details = /** @type {string} */ (sections.pop());
3838
}
3939

packages/svelte/src/internal/client/dev/equality.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ export function init_array_prototype_warnings() {
2020
const test = indexOf.call(get_proxied_value(this), get_proxied_value(item), from_index);
2121

2222
if (test !== -1) {
23-
w.state_proxy_equality_mismatch('array.indexOf(...)');
23+
w.state_proxy_equality_mismatch(
24+
'array.indexOf(...)',
25+
': `array.findIndex(entry => $state.is(entry, item))`'
26+
);
2427
}
2528
}
2629

@@ -42,7 +45,10 @@ export function init_array_prototype_warnings() {
4245
);
4346

4447
if (test !== -1) {
45-
w.state_proxy_equality_mismatch('array.lastIndexOf(...)');
48+
w.state_proxy_equality_mismatch(
49+
'array.lastIndexOf(...)',
50+
': `array.findLastIndex(entry => $state.is(entry, item))`'
51+
);
4652
}
4753
}
4854

@@ -56,7 +62,10 @@ export function init_array_prototype_warnings() {
5662
const test = includes.call(get_proxied_value(this), get_proxied_value(item), from_index);
5763

5864
if (test) {
59-
w.state_proxy_equality_mismatch('array.includes(...)');
65+
w.state_proxy_equality_mismatch(
66+
'array.includes(...)',
67+
': `array.some(entry => $state.is(entry, item))`'
68+
);
6069
}
6170
}
6271

@@ -79,7 +88,7 @@ export function init_array_prototype_warnings() {
7988
*/
8089
export function strict_equals(a, b, equal = true) {
8190
if ((a === b) !== (get_proxied_value(a) === get_proxied_value(b))) {
82-
w.state_proxy_equality_mismatch(equal ? '===' : '!==');
91+
w.state_proxy_equality_mismatch(equal ? '===' : '!==', '');
8392
}
8493

8594
return (a === b) === equal;
@@ -93,7 +102,7 @@ export function strict_equals(a, b, equal = true) {
93102
*/
94103
export function equals(a, b, equal = true) {
95104
if ((a == b) !== (get_proxied_value(a) == get_proxied_value(b))) {
96-
w.state_proxy_equality_mismatch(equal ? '==' : '!=');
105+
w.state_proxy_equality_mismatch(equal ? '==' : '!=', '');
97106
}
98107

99108
return (a == b) === equal;

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,13 @@ export function ownership_invalid_mutation(component, owner) {
114114
}
115115

116116
/**
117-
* Reactive `$state(...)` proxies and the values they proxy have different identities. Because of this, comparisons with `%operator%` will produce unexpected results. Consider using `$state.is(a, b)` instead
117+
* Reactive `$state(...)` proxies and the values they proxy have different identities. Because of this, comparisons with `%operator%` will produce unexpected results. Consider using `$state.is(a, b)` instead%details%
118118
* @param {string} operator
119+
* @param {string} details
119120
*/
120-
export function state_proxy_equality_mismatch(operator) {
121+
export function state_proxy_equality_mismatch(operator, details) {
121122
if (DEV) {
122-
console.warn(`%c[svelte] state_proxy_equality_mismatch\n%cReactive \`$state(...)\` proxies and the values they proxy have different identities. Because of this, comparisons with \`${operator}\` will produce unexpected results. Consider using \`$state.is(a, b)\` instead`, bold, normal);
123+
console.warn(`%c[svelte] state_proxy_equality_mismatch\n%cReactive \`$state(...)\` proxies and the values they proxy have different identities. Because of this, comparisons with \`${operator}\` will produce unexpected results. Consider using \`$state.is(a, b)\` instead${details}`, bold, normal);
123124
} else {
124125
// TODO print a link to the documentation
125126
console.warn("state_proxy_equality_mismatch");

0 commit comments

Comments
 (0)