From 1f37c02f918d6fa4d8a14de5d6868228e61dd05a Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Fri, 21 Mar 2025 14:25:46 +0000 Subject: [PATCH] fix: ensure toStore root effect is connected to correct parent effect (#15574) * fix: ensure toStore root effect is connected to correct parent effect * prettier --------- Co-authored-by: Rich Harris --- .changeset/twelve-bananas-destroy.md | 5 +++ packages/svelte/src/store/index-client.js | 35 +++++++++++++++---- .../samples/toStore-subscribe2/_config.js | 16 +++++++++ .../samples/toStore-subscribe2/main.svelte | 11 ++++++ 4 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 .changeset/twelve-bananas-destroy.md create mode 100644 packages/svelte/tests/runtime-runes/samples/toStore-subscribe2/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/toStore-subscribe2/main.svelte diff --git a/.changeset/twelve-bananas-destroy.md b/.changeset/twelve-bananas-destroy.md new file mode 100644 index 0000000000..873ee21877 --- /dev/null +++ b/.changeset/twelve-bananas-destroy.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: ensure toStore root effect is connected to correct parent effect diff --git a/packages/svelte/src/store/index-client.js b/packages/svelte/src/store/index-client.js index ae6806ec76..2f0a1a831a 100644 --- a/packages/svelte/src/store/index-client.js +++ b/packages/svelte/src/store/index-client.js @@ -6,6 +6,12 @@ import { } from '../internal/client/reactivity/effects.js'; import { get, writable } from './shared/index.js'; import { createSubscriber } from '../reactivity/create-subscriber.js'; +import { + active_effect, + active_reaction, + set_active_effect, + set_active_reaction +} from '../internal/client/runtime.js'; export { derived, get, readable, readonly, writable } from './shared/index.js'; @@ -39,19 +45,34 @@ export { derived, get, readable, readonly, writable } from './shared/index.js'; * @returns {Writable | Readable} */ export function toStore(get, set) { - let init_value = get(); + var effect = active_effect; + var reaction = active_reaction; + var init_value = get(); + const store = writable(init_value, (set) => { // If the value has changed before we call subscribe, then // we need to treat the value as already having run - let ran = init_value !== get(); + var ran = init_value !== get(); // TODO do we need a different implementation on the server? - const teardown = effect_root(() => { - render_effect(() => { - const value = get(); - if (ran) set(value); + var teardown; + // Apply the reaction and effect at the time of toStore being called + var previous_reaction = active_reaction; + var previous_effect = active_effect; + set_active_reaction(reaction); + set_active_effect(effect); + + try { + teardown = effect_root(() => { + render_effect(() => { + const value = get(); + if (ran) set(value); + }); }); - }); + } finally { + set_active_reaction(previous_reaction); + set_active_effect(previous_effect); + } ran = true; diff --git a/packages/svelte/tests/runtime-runes/samples/toStore-subscribe2/_config.js b/packages/svelte/tests/runtime-runes/samples/toStore-subscribe2/_config.js new file mode 100644 index 0000000000..bc1793e7a4 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/toStore-subscribe2/_config.js @@ -0,0 +1,16 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + let btn = target.querySelector('button'); + + btn?.click(); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + `
Count 1!
Count from store 1!
` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/toStore-subscribe2/main.svelte b/packages/svelte/tests/runtime-runes/samples/toStore-subscribe2/main.svelte new file mode 100644 index 0000000000..82d20105b8 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/toStore-subscribe2/main.svelte @@ -0,0 +1,11 @@ + + +
Count {counter}!
+
Count from store {$count}!
+ +