fix: execute uninitialized derived even if it's destroyed (#18228)

Turns out there are a few unavoidable cases where we have to execute the
derived even if we otherwise wouldn't, because of its lazy nature. 
Fixes #18139
pull/18239/head
Simon H 2 weeks ago committed by GitHub
parent eb10a70cf1
commit 1e899cba35
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: execute uninitialized derived even if it's destroyed

@ -338,7 +338,12 @@ export function execute_derived(derived) {
var prev_active_effect = active_effect;
var parent = derived.parent;
if (!is_destroying_effect && parent !== null && (parent.f & (DESTROYED | INERT)) !== 0) {
if (
!is_destroying_effect &&
parent !== null &&
derived.v !== UNINITIALIZED && // if it was never evaluated before, it's guaranteed to fail downstream, so we try to execute instead
(parent.f & (DESTROYED | INERT)) !== 0
) {
w.derived_inert();
return derived.v;

@ -0,0 +1,10 @@
<script>
import { fly } from 'svelte/transition';
// Not read before the outro, by which time the derived is destroyed
let duration = $derived(10);
</script>
<div in:fly={{ duration: 10 }} out:fly={{ duration }}>
hello
</div>

@ -0,0 +1,32 @@
import { flushSync } from 'svelte';
import { raf } from '../../../animation-helpers';
import { test } from '../../test';
export default test({
async test({ assert, target }) {
const [fly_in, fly_out] = target.querySelectorAll('button');
fly_in.click();
flushSync();
raf.tick(25);
assert.htmlEqual(
target.innerHTML,
`
<button>fly in</button>
<button>fly out</button>
<div style="">hello</div>
`
);
fly_out.click();
flushSync();
raf.tick(50);
assert.htmlEqual(
target.innerHTML,
`
<button>fly in</button>
<button>fly out</button>
`
);
}
});

@ -0,0 +1,11 @@
<script>
import Child from './Child.svelte';
let show = $state(false);
</script>
<button onclick={() => (show = true)}>fly in</button>
<button onclick={() => (show = false)}>fly out</button>
{#if show}
<Child />
{/if}
Loading…
Cancel
Save