Skip to content

Commit

Permalink
docs: tweak $state.is warning (#12599)
Browse files Browse the repository at this point in the history
Also add a detailed explanation which can later appear on the docs site

closes #11556
  • Loading branch information
dummdidumm committed Jul 25, 2024
1 parent afa3128 commit 3515776
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 10 deletions.
22 changes: 21 additions & 1 deletion packages/svelte/messages/client-warnings/warnings.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,24 @@
## state_proxy_equality_mismatch

> 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
> 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%
`$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`:

```svelte
<script>
let object = { foo: 'bar' };
let state_object = $state(object);
object === state_object; // always false
</script>
```

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:

```svelte
<script>
let object = { foo: 'bar' };
let state_object = $state(object);
$state.is(object, state_object); // true
</script>
```
2 changes: 1 addition & 1 deletion packages/svelte/scripts/process-messages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ for (const category of fs.readdirSync('messages')) {

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

Expand Down
19 changes: 14 additions & 5 deletions packages/svelte/src/internal/client/dev/equality.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ export function init_array_prototype_warnings() {
const test = indexOf.call(get_proxied_value(this), get_proxied_value(item), from_index);

if (test !== -1) {
w.state_proxy_equality_mismatch('array.indexOf(...)');
w.state_proxy_equality_mismatch(
'array.indexOf(...)',
': `array.findIndex(entry => $state.is(entry, item))`'
);
}
}

Expand All @@ -42,7 +45,10 @@ export function init_array_prototype_warnings() {
);

if (test !== -1) {
w.state_proxy_equality_mismatch('array.lastIndexOf(...)');
w.state_proxy_equality_mismatch(
'array.lastIndexOf(...)',
': `array.findLastIndex(entry => $state.is(entry, item))`'
);
}
}

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

if (test) {
w.state_proxy_equality_mismatch('array.includes(...)');
w.state_proxy_equality_mismatch(
'array.includes(...)',
': `array.some(entry => $state.is(entry, item))`'
);
}
}

Expand All @@ -79,7 +88,7 @@ export function init_array_prototype_warnings() {
*/
export function strict_equals(a, b, equal = true) {
if ((a === b) !== (get_proxied_value(a) === get_proxied_value(b))) {
w.state_proxy_equality_mismatch(equal ? '===' : '!==');
w.state_proxy_equality_mismatch(equal ? '===' : '!==', '');
}

return (a === b) === equal;
Expand All @@ -93,7 +102,7 @@ export function strict_equals(a, b, equal = true) {
*/
export function equals(a, b, equal = true) {
if ((a == b) !== (get_proxied_value(a) == get_proxied_value(b))) {
w.state_proxy_equality_mismatch(equal ? '==' : '!=');
w.state_proxy_equality_mismatch(equal ? '==' : '!=', '');
}

return (a == b) === equal;
Expand Down
7 changes: 4 additions & 3 deletions packages/svelte/src/internal/client/warnings.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,13 @@ export function ownership_invalid_mutation(component, owner) {
}

/**
* 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
* 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%
* @param {string} operator
* @param {string} details
*/
export function state_proxy_equality_mismatch(operator) {
export function state_proxy_equality_mismatch(operator, details) {
if (DEV) {
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);
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);
} else {
// TODO print a link to the documentation
console.warn("state_proxy_equality_mismatch");
Expand Down

0 comments on commit 3515776

Please sign in to comment.