diff --git a/.changeset/strong-berries-fry.md b/.changeset/strong-berries-fry.md new file mode 100644 index 000000000000..60dbb290a854 --- /dev/null +++ b/.changeset/strong-berries-fry.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: store forked derived values diff --git a/packages/svelte/src/internal/client/reactivity/batch.js b/packages/svelte/src/internal/client/reactivity/batch.js index 22526df7c1f2..8f63922ab26e 100644 --- a/packages/svelte/src/internal/client/reactivity/batch.js +++ b/packages/svelte/src/internal/client/reactivity/batch.js @@ -958,12 +958,15 @@ export function fork(fn) { var batch = Batch.ensure(); batch.is_fork = true; + batch_values = new Map(); var committed = false; var settled = batch.settled(); flushSync(fn); + batch_values = null; + // revert state changes for (var [source, value] of batch.previous) { source.v = value; diff --git a/packages/svelte/src/internal/client/reactivity/deriveds.js b/packages/svelte/src/internal/client/reactivity/deriveds.js index 39e02be7649e..3bf38bf0b2a4 100644 --- a/packages/svelte/src/internal/client/reactivity/deriveds.js +++ b/packages/svelte/src/internal/client/reactivity/deriveds.js @@ -378,7 +378,7 @@ export function update_derived(derived) { if (batch_values !== null) { // only cache the value if we're in a tracking context, otherwise we won't // clear the cache in `mark_reactions` when dependencies are updated - if (effect_tracking()) { + if (effect_tracking() || current_batch?.is_fork) { batch_values.set(derived, value); } } else { diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index 5ece0d79b6b8..6b5e38bc6c22 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -43,7 +43,13 @@ import { set_dev_stack } from './context.js'; import * as w from './warnings.js'; -import { Batch, batch_values, flushSync, schedule_effect } from './reactivity/batch.js'; +import { + Batch, + batch_values, + current_batch, + flushSync, + schedule_effect +} from './reactivity/batch.js'; import { handle_error } from './error-handling.js'; import { UNINITIALIZED } from '../../constants.js'; import { captured_signals } from './legacy.js'; @@ -611,7 +617,10 @@ export function get(signal) { return value; } - } else if (is_derived && !batch_values?.has(signal)) { + } else if ( + is_derived && + (!batch_values?.has(signal) || (current_batch?.is_fork && !effect_tracking())) + ) { derived = /** @type {Derived} */ (signal); if (is_dirty(derived)) { diff --git a/packages/svelte/tests/runtime-runes/samples/fork-derived-value-immediate/_config.js b/packages/svelte/tests/runtime-runes/samples/fork-derived-value-immediate/_config.js new file mode 100644 index 000000000000..4f7ff673d6c6 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/fork-derived-value-immediate/_config.js @@ -0,0 +1,13 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + skip_no_async: true, + async test({ assert, target, logs }) { + const fork = target.querySelector('button'); + + fork?.click(); + flushSync(); + assert.deepEqual(logs, [1, 2]); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/fork-derived-value-immediate/main.svelte b/packages/svelte/tests/runtime-runes/samples/fork-derived-value-immediate/main.svelte new file mode 100644 index 000000000000..2adb83b73515 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/fork-derived-value-immediate/main.svelte @@ -0,0 +1,15 @@ + + +