breaking: array proxy toPrimitive is no longer reactive

pull/13538/head
Dominic Gannaway 2 years ago
parent 2b0741fa11
commit b2b3399419

@ -0,0 +1,5 @@
---
'svelte': patch
---
breaking: array proxy toPrimitive is no longer reactive

@ -1,6 +1,6 @@
/** @import { ProxyMetadata, ProxyStateObject, Source } from '#client' */ /** @import { ProxyMetadata, ProxyStateObject, Source } from '#client' */
import { DEV } from 'esm-env'; import { DEV } from 'esm-env';
import { get, component_context, active_effect } from './runtime.js'; import { get, component_context, active_effect, untrack } from './runtime.js';
import { import {
array_prototype, array_prototype,
get_descriptor, get_descriptor,
@ -115,6 +115,12 @@ export function proxy(value, parent = null, prev) {
if (DEV && prop === STATE_SYMBOL_METADATA) { if (DEV && prop === STATE_SYMBOL_METADATA) {
return metadata; return metadata;
} }
// We untrack Symbol.toPrimitive cases. If people want explicit reactivity, they should
// use toString() or some other coercion method instead
if (is_proxied_array && prop === Symbol.toPrimitive) {
return (/** @type {'string' | 'number' | 'default'} */ hint) =>
untrack(() => (hint === 'number' ? Number(target) : String(target)));
}
if (prop === STATE_SYMBOL) { if (prop === STATE_SYMBOL) {
return value; return value;

@ -18,4 +18,4 @@
</script> </script>
<button onclick={() => (state.data.list.push(1))}>update</button> <button onclick={() => (state.data.list.push(1))}>update</button>
{state.data.list} {state.data.list.toString()}

@ -26,4 +26,4 @@
</script> </script>
<p>props: {p0} {p1} {p2} {p3} {p4} {p5} {p6} {p7}</p> <p>props: {p0} {p1} {p2} {p3} {p4} {p5} {p6} {p7}</p>
<p>log: {log}</p> <p>log: {log.toString()}</p>

@ -0,0 +1,30 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
export default test({
html: `
<button>add</button><ul><li>1,2,3</li><li>1,2,3</li><li>text
1,2,3</li><li>1,2,3</li><li>1,2,3</li><li title="1,2,3"></li><li title="1,2,3"></li><li><input readonly="" type="text"></li><li><input readonly="" type="text"></li></ul>
`,
ssrHtml: `
<button>add</button><ul><li>1,2,3</li><li>1,2,3</li><li>text
1,2,3</li><li>1,2,3</li><li>1,2,3</li><li title="1,2,3"></li><li title="1,2,3"></li><li><input readonly="" type="text" value="1,2,3"></li><li><input readonly="" type="text" value="1,2,3"></li></ul>
`,
test({ assert, target }) {
const [btn1] = target.querySelectorAll('button');
flushSync(() => {
btn1?.click();
});
assert.htmlEqual(
target.innerHTML,
`
<button>add</button><ul><li>1,2,3</li><li>1,2,3,4</li><li>text
1,2,3</li><li>1,2,3</li><li>1,2,3,4</li><li title="1,2,3"></li><li title="1,2,3,4"></li><li><input readonly="" type="text"></li><li><input readonly="" type="text"></li></ul>
`
);
}
});

@ -0,0 +1,21 @@
<script>
let array = $state([1,2,3]);
function addToArray() {
array.push(array.length+1);
}
</script>
<button onclick={addToArray}>add</button>
<ul>
<li>{@html array}</li>
<li>{@html array?.toString()}</li>
<li>text {array}</li>
<li>{array}</li>
<li>{array?.toString()}</li>
<li title={array}></li>
<li title={array?.toString()}></li>
<li><input type="text" value={array} readonly/> </li>
<li><input type="text" value={array?.toString()} readonly/> </li>
</ul>
Loading…
Cancel
Save