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>
pull/17228/head
Paolo Ricciuti 9 months ago committed by GitHub
parent 53bbe3462b
commit ea8838e96f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: store forked derived values

@ -959,12 +959,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;

@ -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 {

@ -44,7 +44,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';
@ -612,7 +618,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)) {

@ -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]);
}
});

@ -0,0 +1,15 @@
<script>
import { fork } from "svelte";
let state = $state(0);
let count = $derived(state);
</script>
<button onclick={() => {
fork(() => {
state++;
console.log(count);
state++;
console.log(count);
});
}}>fork</button>
Loading…
Cancel
Save