Skip to content

Commit ea8838e

Browse files
fix: store forked derived values (#17212)
We have to take non-tracking contexts into account, especially while in the original `fork(() => ...)` context. Closes #17206 --------- Co-authored-by: Simon Holthausen <simon.holthausen@vercel.com>
1 parent 53bbe34 commit ea8838e

File tree

6 files changed

+48
-3
lines changed

6 files changed

+48
-3
lines changed

.changeset/strong-berries-fry.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: store forked derived values

packages/svelte/src/internal/client/reactivity/batch.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -959,12 +959,15 @@ export function fork(fn) {
959959

960960
var batch = Batch.ensure();
961961
batch.is_fork = true;
962+
batch_values = new Map();
962963

963964
var committed = false;
964965
var settled = batch.settled();
965966

966967
flushSync(fn);
967968

969+
batch_values = null;
970+
968971
// revert state changes
969972
for (var [source, value] of batch.previous) {
970973
source.v = value;

packages/svelte/src/internal/client/reactivity/deriveds.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ export function update_derived(derived) {
378378
if (batch_values !== null) {
379379
// only cache the value if we're in a tracking context, otherwise we won't
380380
// clear the cache in `mark_reactions` when dependencies are updated
381-
if (effect_tracking()) {
381+
if (effect_tracking() || current_batch?.is_fork) {
382382
batch_values.set(derived, value);
383383
}
384384
} else {

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,13 @@ import {
4444
set_dev_stack
4545
} from './context.js';
4646
import * as w from './warnings.js';
47-
import { Batch, batch_values, flushSync, schedule_effect } from './reactivity/batch.js';
47+
import {
48+
Batch,
49+
batch_values,
50+
current_batch,
51+
flushSync,
52+
schedule_effect
53+
} from './reactivity/batch.js';
4854
import { handle_error } from './error-handling.js';
4955
import { UNINITIALIZED } from '../../constants.js';
5056
import { captured_signals } from './legacy.js';
@@ -612,7 +618,10 @@ export function get(signal) {
612618

613619
return value;
614620
}
615-
} else if (is_derived && !batch_values?.has(signal)) {
621+
} else if (
622+
is_derived &&
623+
(!batch_values?.has(signal) || (current_batch?.is_fork && !effect_tracking()))
624+
) {
616625
derived = /** @type {Derived} */ (signal);
617626

618627
if (is_dirty(derived)) {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { flushSync } from 'svelte';
2+
import { test } from '../../test';
3+
4+
export default test({
5+
skip_no_async: true,
6+
async test({ assert, target, logs }) {
7+
const fork = target.querySelector('button');
8+
9+
fork?.click();
10+
flushSync();
11+
assert.deepEqual(logs, [1, 2]);
12+
}
13+
});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<script>
2+
import { fork } from "svelte";
3+
4+
let state = $state(0);
5+
let count = $derived(state);
6+
</script>
7+
8+
<button onclick={() => {
9+
fork(() => {
10+
state++;
11+
console.log(count);
12+
state++;
13+
console.log(count);
14+
});
15+
}}>fork</button>

0 commit comments

Comments
 (0)