fix: ensure proxy is updated before notifying listeners (#10267)

fixes #10264
fixes #10265
pull/10270/head
Simon H 8 months ago committed by GitHub
parent 036e88f1f7
commit 14bf4b4b2c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: ensure proxy is updated before notifying listeners

@ -244,26 +244,32 @@ const handler = {
const is_array = metadata.a;
const not_has = !(prop in target);
// variable.length = value -> clear all signals with index >= value
if (is_array && prop === 'length') {
for (let i = value; i < target.length; i += 1) {
const s = metadata.s.get(i + '');
if (s !== undefined) set(s, UNINITIALIZED);
}
}
if (not_has) {
update(metadata.v);
}
// Set the new value before updating any signals so that any listeners get the new value
// @ts-ignore
target[prop] = value;
// If we have mutated an array directly, we might need to
// signal that length has also changed too.
if (is_array && not_has) {
const ls = metadata.s.get('length');
const length = target.length;
if (ls !== undefined && ls.v !== length) {
set(ls, length);
if (not_has) {
// If we have mutated an array directly, we might need to
// signal that length has also changed. Do it before updating metadata
// to ensure that iterating over the array as a result of a metadata update
// will not cause the length to be out of sync.
if (is_array) {
const ls = metadata.s.get('length');
const length = target.length;
if (ls !== undefined && ls.v !== length) {
set(ls, length);
}
}
update(metadata.v);
}
return true;

@ -0,0 +1,33 @@
import { test } from '../../test';
/**
* @type {any[]}
*/
let log;
/**
* @type {typeof console.log}}
*/
let original_log;
export default test({
compileOptions: {
dev: true
},
before_test() {
log = [];
original_log = console.log;
console.log = (...v) => {
log.push(...v);
};
},
after_test() {
console.log = original_log;
},
async test({ assert, target }) {
const [btn] = target.querySelectorAll('button');
btn.click();
await Promise.resolve();
assert.deepEqual(log, ['init', {}, 'init', [], 'update', { x: 'hello' }, 'update', ['hello']]);
}
});

@ -0,0 +1,15 @@
<script>
let obj = $state({});
let array = $state([]);
$inspect(obj);
$inspect(array);
</script>
<button
onclick={() => {
obj.x = "hello";
array[0] = "hello";
}}>
add prop
</button>
Loading…
Cancel
Save