Skip to content

Commit 2de7412

Browse files
trueadmdummdidumm
andauthored
fix: correctly handle proxied signal writes before reads (#10612)
* fix: correctly handle proxied signal writes before reads * managed * Update packages/svelte/src/internal/client/proxy.js Co-authored-by: Simon H <[email protected]> --------- Co-authored-by: Simon H <[email protected]>
1 parent 506196b commit 2de7412

File tree

4 files changed

+46
-5
lines changed

4 files changed

+46
-5
lines changed

.changeset/rude-ghosts-tickle.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte": patch
3+
---
4+
5+
fix: correctly handle proxied signal writes before reads

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

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import {
66
updating_derived,
77
batch_inspect,
88
current_component_context,
9-
set_ignore_mutation_validation
9+
set_ignore_mutation_validation,
10+
untrack
1011
} from './runtime.js';
1112
import { effect_active } from './reactivity/computations.js';
1213
import {
@@ -261,10 +262,21 @@ const state_proxy_handler = {
261262
return has;
262263
},
263264

264-
set(target, prop, value) {
265+
set(target, prop, value, receiver) {
265266
const metadata = target[STATE_SYMBOL];
266-
const s = metadata.s.get(prop);
267-
if (s !== undefined) set(s, proxy(value, metadata.i, metadata.o));
267+
let s = metadata.s.get(prop);
268+
// If we haven't yet created a source for this property, we need to ensure
269+
// we do so otherwise if we read it later, then the write won't be tracked and
270+
// the heuristics of effects will be different vs if we had read the proxied
271+
// object property before writing to that property.
272+
if (s === undefined && effect_active()) {
273+
// the read creates a signal
274+
untrack(() => receiver[prop]);
275+
s = metadata.s.get(prop);
276+
}
277+
if (s !== undefined) {
278+
set(s, proxy(value, metadata.i, metadata.o));
279+
}
268280
const is_array = metadata.a;
269281
const not_has = !(prop in target);
270282

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,7 @@ export function get(signal) {
744744
current_untracked_writes !== null &&
745745
current_effect !== null &&
746746
(current_effect.f & CLEAN) !== 0 &&
747+
(current_effect.f & MANAGED) === 0 &&
747748
current_untracked_writes.includes(signal)
748749
) {
749750
set_signal_status(current_effect, DIRTY);
@@ -975,7 +976,8 @@ export function set_signal_value(signal, value) {
975976
!ignore_mutation_validation &&
976977
current_effect !== null &&
977978
current_effect.c === null &&
978-
(current_effect.f & CLEAN) !== 0
979+
(current_effect.f & CLEAN) !== 0 &&
980+
(current_effect.f & MANAGED) === 0
979981
) {
980982
if (current_dependencies !== null && current_dependencies.includes(signal)) {
981983
set_signal_status(current_effect, DIRTY);

packages/svelte/tests/signals/test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
} from '../../src/internal/client/reactivity/computations';
99
import { source } from '../../src/internal/client/reactivity/sources';
1010
import type { ComputationSignal } from '../../src/internal/client/types';
11+
import { proxy } from '../../src/internal/client/proxy';
1112

1213
/**
1314
* @param runes runes mode
@@ -333,4 +334,25 @@ describe('signals', () => {
333334
assert.equal(errored, true);
334335
};
335336
});
337+
338+
test('schedules rerun when writing to signal before reading it', (runes) => {
339+
if (!runes) return () => {};
340+
341+
const value = proxy({ arr: [] });
342+
user_effect(() => {
343+
value.arr = [];
344+
value.arr;
345+
});
346+
347+
return () => {
348+
let errored = false;
349+
try {
350+
$.flushSync();
351+
} catch (e: any) {
352+
assert.include(e.message, 'ERR_SVELTE_TOO_MANY_UPDATES');
353+
errored = true;
354+
}
355+
assert.equal(errored, true);
356+
};
357+
});
336358
});

0 commit comments

Comments
 (0)