restore resetting effects to CLEAN in is_dirty while time travelling

Effects left MAYBE_DIRTY are forced to re-run when a paused branch is resumed.
async-another-try-pt-1-prune
Rich Harris 2 days ago
parent 336d1ef608
commit 69f0bb549f
No known key found for this signature in database

@ -185,8 +185,10 @@ export function is_dirty(reaction) {
if (
(flags & CONNECTED) !== 0 &&
// During time traveling we don't want to reset the status so that
// traversal of the graph in the other batches still happens
batch_values === null
// traversal of the graph in the other batches still happens. Effects
// can be reset because block/async effects execute right away and others
// are deferred and re-dirtied as needed.
(batch_values === null || (flags & DERIVED) === 0)
) {
set_signal_status(reaction, CLEAN);
}

@ -0,0 +1,9 @@
<script>
let { big } = $props();
$effect(() => {
console.log(`effect ${big}`);
});
</script>
<p>child</p>

@ -0,0 +1,37 @@
import { tick } from 'svelte';
import { test } from '../../test';
export default test({
mode: ['client'],
async test({ assert, target, logs, raf }) {
await tick();
const [x, s, toggle, shift] = target.querySelectorAll('button');
assert.deepEqual(logs, ['effect false']);
// keep an earlier batch pending, so that the next one commits while time travelling
x.click();
await tick();
// `big` stays `false`, so the effect must not re-run
s.click();
await tick();
assert.deepEqual(logs, ['effect false']);
shift.click();
await tick();
assert.htmlEqual(
target.innerHTML,
'<button>x</button><button>s</button><button>toggle</button><button>shift</button><p>1</p><div><p>child</p></div>'
);
// outro, then reintro before the outro finished: the branch is resumed
toggle.click();
await tick();
raf.tick(50);
toggle.click();
await tick();
raf.tick(200);
assert.deepEqual(logs, ['effect false']);
}
});

@ -0,0 +1,29 @@
<script>
import { fade } from 'svelte/transition';
import Child from './Child.svelte';
let x = $state(0);
let s = $state(0);
let show = $state(true);
const big = $derived(s > 100);
const queued = [];
function push(v) {
if (v === 0) return v;
return new Promise((resolve) => queued.push(() => resolve(v)));
}
</script>
<button onclick={() => x++}>x</button>
<button onclick={() => s++}>s</button>
<button onclick={() => (show = !show)}>toggle</button>
<button onclick={() => queued.shift()?.()}>shift</button>
<p>{await push(x)}</p>
{#if show}
<div transition:fade={{ duration: 100 }}>
<Child {big} />
</div>
{/if}
Loading…
Cancel
Save