<script>
let show = true;
setTimeout(() => (show = false));
</script>
<div>
{#each [""] as v (v)}
{#if show}<slot></slot>{/if}
{/each}
</div>
Running this causes an error when an update is triggered by the reactive assignment in setTimeout:
Chrome: Uncaught (in promise) TypeError: Cannot read property 'd' of null
Safari: Unhandled Promise Rejection: TypeError: null is not an object (evaluating 'if_block.d')
If the each block is not keyed (I remove (v)), there's no error.
Such an intricate bug. Great find!
The change handler of the each block has this code in it:
p(changed, ctx) {
// ...
group_outros();
on_outro(() => {
if_block.d(1);
if_block = null;
});
if_block.o(1);
check_outros();
}
And the change handler of the entire component has this code in it:
p(changed, ctx) {
// ...
each_blocks = update_keyed_each(/* ... */);
check_outros();
}
When show is changed the check_outros in the each block change handler is called and it sets if_block to null, so when the component check_outros is called directly after, if_block is null and the error is thrown.
I've had the same errors in keyed each which contain if with svelte:self inside.
Maybe, we can just add null-checks to on_outro callbacks?
I did try to add some null-checks to on_outro in IfBlock. Hope it's right way to fix this issue.
I'm getting this error in a keyed each with an if block which contains a component:
https://svelte.dev/repl/f737684ba6534637901724ce9daca33f?version=3.4.4
Steps to reproduce:
JS error in Console: TypeError: if_block is null.
(Removing the key avoids the issue.)
The only workaround I've found to get around this issue is to move the
{#if shown}...{/if}
into the component.
Just ran into the same variation as @fvsch. Here's a slightly smaller reproduction of the issue:
https://svelte.dev/repl/35fdcf7ddad1403abf3ec6eeee108e57?version=3.4.4
Note that the problem goes away if you remove the key (item) or don't use a component (say, replace <Item></Item> with <li></li>).
All three of the reproductions in this issue look to be fixed in 3.6.7, presumably by #3172. Closing.
Most helpful comment
Such an intricate bug. Great find!
The change handler of the each block has this code in it:
And the change handler of the entire component has this code in it:
When
showis changed thecheck_outrosin the each block change handler is called and it setsif_blocktonull, so when the componentcheck_outrosis called directly after,if_blockisnulland the error is thrown.