fix: always mark reactions of deriveds (#16457)

* tweak

* fix

* test

* changeset
pull/16453/head
Rich Harris 2 months ago committed by GitHub
parent 53fdd0f93a
commit d3a01bd5a7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: always mark reactions of deriveds

@ -337,7 +337,9 @@ export function update_derived(derived) {
// don't mark derived clean if we're reading it inside a
// cleanup function, or it will cache a stale value
if (is_destroying_effect) return;
if (is_destroying_effect) {
return;
}
if (batch_deriveds !== null) {
batch_deriveds.set(derived, derived.v);

@ -314,9 +314,6 @@ function mark_reactions(signal, status) {
var reaction = reactions[i];
var flags = reaction.f;
// Skip any effects that are already dirty
if ((flags & DIRTY) !== 0) continue;
// In legacy mode, skip the current effect to prevent infinite loops
if (!runes && reaction === active_effect) continue;
@ -326,15 +323,15 @@ function mark_reactions(signal, status) {
continue;
}
set_signal_status(reaction, status);
// don't set a DIRTY reaction to MAYBE_DIRTY
if ((flags & DIRTY) === 0) {
set_signal_status(reaction, status);
}
// If the signal a) was previously clean or b) is an unowned derived, then mark it
if ((flags & (CLEAN | UNOWNED)) !== 0) {
if ((flags & DERIVED) !== 0) {
mark_reactions(/** @type {Derived} */ (reaction), MAYBE_DIRTY);
} else {
schedule_effect(/** @type {Effect} */ (reaction));
}
if ((flags & DERIVED) !== 0) {
mark_reactions(/** @type {Derived} */ (reaction), MAYBE_DIRTY);
} else if ((flags & DIRTY) === 0) {
schedule_effect(/** @type {Effect} */ (reaction));
}
}
}

@ -0,0 +1,56 @@
import { tick } from 'svelte';
import { test } from '../../test';
export default test({
async test({ assert, target }) {
await tick();
const [a, b, update] = target.querySelectorAll('button');
assert.htmlEqual(
target.innerHTML,
`
<button>a</button>
<button>b</button>
<button>0</button>
<h1>a</h1>
`
);
b.click();
await tick();
assert.htmlEqual(
target.innerHTML,
`
<button>a</button>
<button>b</button>
<button>0</button>
<h1>b</h1>
`
);
update.click();
await tick();
assert.htmlEqual(
target.innerHTML,
`
<button>a</button>
<button>b</button>
<button>1</button>
<h1>b</h1>
`
);
a.click();
await tick();
assert.htmlEqual(
target.innerHTML,
`
<button>a</button>
<button>b</button>
<button>1</button>
<h1>a</h1>
`
);
}
});

@ -0,0 +1,26 @@
<script>
let object = $state(null);
let count = $state(0);
const condition = $derived(object === null);
</script>
<svelte:boundary>
<button onclick={() => (object = null)}>a</button>
<button onclick={() => (object = {})}>b</button>
<button onclick={async () => {
count++;
await Promise.resolve();
object = {};
}}>{await count}</button>
{#if condition}
<h1>a</h1>
{:else}
<h1>b</h1>
{/if}
{#snippet pending()}{/snippet}
</svelte:boundary>
Loading…
Cancel
Save