kit
kit copied to clipboard
Layout with transition not unmounted on navigation
Describe the bug
When routing from /b
to /
using an anchor element, the /b/+page.svelte
component does not get unmounted.
<!-- /routes/b/+layout.svelte -->
<script>
import { page } from '$app/stores';
import { slide } from 'svelte/transition';
$: isB = $page.url.pathname === '/b';
</script>
<slot />
{#if isB}
<div transition:slide><a href="/">Home</a></div>
{/if}
<!-- /routes/b/+page.svelte -->
<div><a href="/">Home</a></div>
- Expected behavior: all
/routes/b
related components should be unmounted. - Actual behavior: the
<div><a href="/">Home</a></div>
component remains.
Reproduction
Check Stackblitz
Instructions
- Press
/b
- Press
/a
Expected behavior
/a
/b - /a/+page.svelte
Actual behavior
/a
/a - /b/+page.svelte
/b - /a/+page.svelte
Logs
No response
System Info
System:
OS: Windows 10 10.0.22621
CPU: (8) x64 AMD Ryzen 7 4700U with Radeon Graphics
Memory: 3.79 GB / 15.32 GB
Binaries:
Node: 18.12.0 - C:\Program Files\nodejs\node.EXE
npm: 8.19.2 - C:\Program Files\nodejs\npm.CMD
Browsers:
Edge: Spartan (44.22621.675.0), Chromium (105.0.1343.53)
Internet Explorer: 11.0.22621.1
Severity
annoyance
Additional Information
- https://github.com/sveltejs/kit/issues/3753#issue-1125425183
While waiting for a fix, you can workaround this by adding local
to the transition:
<script>
import { page } from '$app/stores';
import { slide } from 'svelte/transition';
$: isB = $page.url.pathname === '/b';
</script>
<slot />
{#if isB}
- <li transition:slide><a href="/a"><code>/a</code></a> - <code>/b/+layout.svelte</code></li>
+ <li transition:slide|local><a href="/a"><code>/a</code></a> - <code>/b/+layout.svelte</code></li>
{/if}
But either way, a very interesting bug. I've had similar troubles with navigation and using transitions, but adding local usually fixes them. However, it's still confusing when it happened to me while I was learning Svelte.
+1, but not using a transition. Seeing subsequent pages mount under the previous page. Like, at the bottom of the page. The +layout and +page of the previous page is never unmounted.
![Screen Shot 2022-11-02 at 11 32 06 AM](https://user-images.githubusercontent.com/99897841/199547305-85b53259-f6c0-44cd-8610-f5254057fe10.png)
![Screen Shot 2022-11-02 at 11 32 16 AM](https://user-images.githubusercontent.com/99897841/199547308-781f6d18-b9d2-4eea-86fa-06b7b959ee0b.png)
+1, but not using a transition. Seeing subsequent pages mount under the previous page. Like, at the bottom of the page. The +layout and +page of the child page is never unmounted.
Are you able to identify the cause? Personally curious
Are you able to identify the cause? Personally curious
nope.
Update: found some transitions buried in a component I forgot about 😅 adding the |local
modifier fixed this for me.
In tracking it down, looked like something between @sveltejs/kit
version 521 and 522 is the culprit. v521 worked fine, v522 = layout hell.
I have made a reproducible example (albeit a bit bigger than needed) if you want to play with it: https://stackblitz.com/edit/sveltejs-kit-template-default-1fsbnb
I can't track this down to a recent kit version, going back as far as 450 still reproduces this. I think the issue lies in Svelte core. I can reproduce this with a simple variable that is updated every 10 miliseconds. My guess is that updating the value while transitioning out breaks things.
<script>
import { slide } from 'svelte/transition';
let foo = {t:true}
setInterval(() => foo={t:true}, 10);
</script>
<slot />
{#if foo.t}
<li transition:slide><a href="/a"><code>/a</code></a> - <code>/b/+layout.svelte</code></li>
{/if}
https://stackblitz.com/edit/sveltejs-kit-template-default-8n1tyl?file=package.json,src%2Froutes%2F%2Blayout.svelte,src%2Froutes%2Fb%2F%2Blayout.svelte
possibly related - #7877
Pls Fix!
ugh, just ran into this. very strange bug. pls fix!
I also noticed that one of my pages took 500ms to disappear when navigating out. I tracked it to a component I was using which was using a transition that was not local
. In Svelte 3 and earlier, apparently, the default is global. I think they must have recognized that this is a bad default. Svelte seems very ambitious, but somehow not quite there yet.
I can't track this down to a recent kit version, going back as far as 450 still reproduces this. I think the issue lies in Svelte core. I can reproduce this with a simple variable that is updated every 10 miliseconds. My guess is that updating the value while transitioning out breaks things.
<script> import { slide } from 'svelte/transition'; let foo = {t:true} setInterval(() => foo={t:true}, 10); </script> <slot /> {#if foo.t} <li transition:slide><a href="/a"><code>/a</code></a> - <code>/b/+layout.svelte</code></li> {/if}
It seems to be fixed with Svelte 5. Here's an updated repro. I just updated all dependencies to their latest.
While there may be multiple issues at play (see the many bug reports dealing with transitions), let me clarify what I believe I encountered.
If a Svelte 3 page/layout uses a third-party component (such as svelte-video-player in my case) which internally uses a non-local transition on any of its components, then this transition plays when the page contained the component is destroyed - this is probably as it should be, although likely the developer of the component didn't intend this, and it's creating problems for the user of the component because they have no way to override the transition (let alone that it's confusing and takes a long time to figure out).
But what's clearly a bug (in Svelte 3, probably) is this: not only does the transition play (and delay the hiding of the page that the component is in), but the new page that's being navigated to has already appeared even before all components in the old page have been transitioned out. It appeared under the previous one as described by @mglikesbikes. In my case, the old page/layout did eventually disappear after playing its transition (so this may not be quite the bug described here where the old page doesn't get destroyed at all).
I think the reason they made transitions local by default in Svelte 4 may be this, which is to avoid such unintended effects of components on the pages/layouts containing them.