From 3b2e6eac9a52a89e9981608dc1c8ba4b20419e0d Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Fri, 17 Nov 2023 13:04:12 +0000 Subject: [PATCH] fix: address unowned propagation signal issue (#9510) * fix: address unowned propagation signal issue * Add comments --- .changeset/fifty-steaks-float.md | 5 +++ .../svelte/src/internal/client/runtime.js | 16 ++++--- .../class-state-derived-unowned/_config.js | 45 +++++++++++++++++++ .../class-state-derived-unowned/main.svelte | 36 +++++++++++++++ 4 files changed, 96 insertions(+), 6 deletions(-) create mode 100644 .changeset/fifty-steaks-float.md create mode 100644 packages/svelte/tests/runtime-runes/samples/class-state-derived-unowned/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/class-state-derived-unowned/main.svelte diff --git a/.changeset/fifty-steaks-float.md b/.changeset/fifty-steaks-float.md new file mode 100644 index 0000000000..b100f215be --- /dev/null +++ b/.changeset/fifty-steaks-float.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: address unowned propagation signal issue diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index a67f300b21..67d1593f41 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -895,15 +895,19 @@ function mark_signal_consumers(signal, to_status, force_schedule) { for (i = 0; i < length; i++) { const consumer = consumers[i]; const flags = consumer.flags; - if ( - (flags & DIRTY) !== 0 || - (!runes && consumer === current_effect) || - (!force_schedule && consumer === current_effect) - ) { + const unowned = (flags & UNOWNED) !== 0; + const dirty = (flags & DIRTY) !== 0; + // We skip any effects that are already dirty (but not unowned). Additionally, we also + // skip if the consumer is the same as the current effect (except if we're not in runes or we + // are in force schedule mode). + if ((dirty && !unowned) || ((!force_schedule || !runes) && consumer === current_effect)) { continue; } set_signal_status(consumer, to_status); - if ((flags & CLEAN) !== 0) { + // If the signal is not clean, then skip over it – with the exception of unowned signals that + // are already dirty. Unowned signals might be dirty because they are not captured as part of an + // effect. + if ((flags & CLEAN) !== 0 || (dirty && unowned)) { if ((consumer.flags & IS_EFFECT) !== 0) { schedule_effect(/** @type {import('./types.js').EffectSignal} */ (consumer), false); } else { diff --git a/packages/svelte/tests/runtime-runes/samples/class-state-derived-unowned/_config.js b/packages/svelte/tests/runtime-runes/samples/class-state-derived-unowned/_config.js new file mode 100644 index 0000000000..d73f3351a3 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/class-state-derived-unowned/_config.js @@ -0,0 +1,45 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + // The component context class instance gets shared between tests, strangely, causing hydration to fail? + skip_if_hydrate: 'permanent', + + async test({ assert, target, component }) { + const btn = target.querySelector('button'); + + flushSync(() => { + btn?.click(); + }); + + assert.deepEqual(component.log, [0, 'class trigger false', 'local trigger false', 1]); + + flushSync(() => { + btn?.click(); + }); + + assert.deepEqual(component.log, [0, 'class trigger false', 'local trigger false', 1, 2]); + + flushSync(() => { + btn?.click(); + }); + + assert.deepEqual(component.log, [0, 'class trigger false', 'local trigger false', 1, 2, 3]); + + flushSync(() => { + btn?.click(); + }); + + assert.deepEqual(component.log, [ + 0, + 'class trigger false', + 'local trigger false', + 1, + 2, + 3, + 4, + 'class trigger true', + 'local trigger true' + ]); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/class-state-derived-unowned/main.svelte b/packages/svelte/tests/runtime-runes/samples/class-state-derived-unowned/main.svelte new file mode 100644 index 0000000000..58b96457db --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/class-state-derived-unowned/main.svelte @@ -0,0 +1,36 @@ + + + + +