fix: store forked derived values

forked-derived-values
paoloricciuti 6 hours ago
parent 1aafbc47ff
commit fea81ad68a

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

@ -68,6 +68,14 @@ export let previous_batch = null;
*/
export let batch_values = null;
/**
* When time travelling (i.e. working in one batch, while other batches
* still have ongoing work), we ignore the real values of affected
* signals in favour of their values within the batch
* @type {Map<Value, any> | null}
*/
export let forked_derived_values = null;
// TODO this should really be a property of `batch`
/** @type {Effect[]} */
let queued_root_effects = [];
@ -962,8 +970,12 @@ export function fork(fn) {
var committed = false;
var settled = batch.settled();
forked_derived_values = new Map();
flushSync(fn);
forked_derived_values = null;
// revert state changes
for (var [source, value] of batch.previous) {
source.v = value;

@ -34,7 +34,7 @@ import { async_mode_flag, tracing_mode_flag } from '../../flags/index.js';
import { Boundary } from '../dom/blocks/boundary.js';
import { component_context } from '../context.js';
import { UNINITIALIZED } from '../../../constants.js';
import { batch_values, current_batch } from './batch.js';
import { batch_values, current_batch, forked_derived_values } from './batch.js';
import { unset_context } from './async.js';
import { deferred } from '../../shared/utils.js';
@ -360,8 +360,10 @@ export function update_derived(derived) {
// the underlying value will be updated when the fork is committed.
// otherwise, the next time we get here after a 'real world' state
// change, `derived.equals` may incorrectly return `true`
if (!current_batch?.is_fork) {
if (!forked_derived_values) {
derived.v = value;
} else {
forked_derived_values.set(derived, value);
}
derived.wv = increment_write_version();

@ -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,
flushSync,
forked_derived_values,
schedule_effect
} from './reactivity/batch.js';
import { handle_error } from './error-handling.js';
import { UNINITIALIZED } from '../../constants.js';
import { captured_signals } from './legacy.js';
@ -621,6 +627,10 @@ export function get(signal) {
if (is_updating_effect && effect_tracking() && (derived.f & CONNECTED) === 0) {
reconnect(derived);
}
if (forked_derived_values?.has(derived)) {
return forked_derived_values.get(derived);
}
}
if (batch_values?.has(signal)) {

@ -0,0 +1,15 @@
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');
flushSync(() => {
fork?.click();
});
assert.deepEqual(logs, [1]);
}
});

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