fix: skip derived re-evaluation inside inert effect blocks (#17852)

this is #17850 with changes (for whatever reason I wasn't able to push
direct to the fork) — same test but simplified, and a simpler fix that
doesn't undo the recent (necessary!) changes to the scheduling logic

---------

Co-authored-by: Mattias Granlund <mtsgrd@gmail.com>
pull/17860/head
Rich Harris 7 days ago committed by GitHub
parent 25a1c5368b
commit e3f06f9fc7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: skip derived re-evaluation inside inert effect blocks

@ -10,7 +10,8 @@ import {
ASYNC,
WAS_MARKED,
DESTROYED,
CLEAN
CLEAN,
INERT
} from '#client/constants';
import {
active_reaction,
@ -305,10 +306,22 @@ function get_derived_parent_effect(derived) {
* @returns {T}
*/
export function execute_derived(derived) {
var parent_effect = get_derived_parent_effect(derived);
// don't update `{@const ...}` in an outroing block
if (
!async_mode_flag &&
!is_destroying_effect &&
parent_effect !== null &&
(parent_effect.f & INERT) !== 0
) {
return derived.v;
}
var value;
var prev_active_effect = active_effect;
set_active_effect(get_derived_parent_effect(derived));
set_active_effect(parent_effect);
if (DEV) {
let prev_eager_effects = eager_effects;

@ -0,0 +1,18 @@
import { flushSync, tick } from 'svelte';
import { test } from '../../test';
export default test({
html: '<button>clear</button><div><p>hello</p></div>',
async test({ assert, target, raf, logs }) {
const [button] = target.querySelectorAll('button');
flushSync(() => button.click());
assert.deepEqual(logs, ['hello']);
// Let the transition finish and clean up
raf.tick(100);
assert.htmlEqual(target.innerHTML, '<button>clear</button>');
}
});

@ -0,0 +1,32 @@
<script>
let value = $state('hello');
function compute(v) {
console.log(v);
return { data: v, ready: true };
}
function fade(node) {
return {
duration: 100,
tick: (t) => {
node.style.opacity = String(t);
}
};
}
</script>
<button
onclick={() => {
value = undefined;
}}>clear</button
>
{#if value}
{@const result = compute(value)}
{#if result.ready}
<div out:fade|global>
<p>{result.data}</p>
</div>
{/if}
{/if}
Loading…
Cancel
Save