Skip to content

Astro + Svelte: ViewTransitions do not persist state and do not remove eventlisteners (from version 4.5.0 onward, until 4.4.15 it works) #11970

@CaspianVahagn

Description

@CaspianVahagn

Astro Info

Astro                    v4.15.4
Node                     v20.17.0
System                   Linux (x64)
Package Manager          unknown
Output                   static
Adapter                  none
Integrations             @astrojs/tailwind
                         @astrojs/svelte

If this issue only occurs in one browser, which browser is a problem?

No response

Describe the Bug

When using thetransition:persist directive on svelte-components two errors occur:

  1. The state is not persisting (which is ok since you can opt out with transition:persist-props)
  2. The eventlisteners are not removed (e.g. on:click)

The second issue is extremly problematic, since it will stack all eventlisteners on rerouting:

In the example provided is a simple counter component made with svelte, with the viewtransition persist directive.

<header style="padding:3rem ">
	<a style="color:white" href="/hello">hello</a>
	<a style="color:white" href="/">home</a>
	<Counter client:load transition:persist></Counter>
</header>

Counter.svelte:

<script lang="ts">
	import {sampleState} from "../state/sampleState.ts";
	import {onMount} from "svelte";

	function update(){
		sampleState.update(e => e+1)
		console.log("update")
	}
	onMount(() => {
		console.log("mounted")
	})
</script>
<button style="padding: 1rem;" on:click={update}>{$sampleState}</button>

The update function will be called with each click, multiplied with amount of navigations when the user uses a link to navigate.
The example has two links and pages: "home", "hello".
As soon as you navigate by link, the component gets rerendered and the eventlisteners of on:click will not get destroyed.
The component will be mounted multiple times (per navigation) but the eventlistener will not get destroyed, leading to the "update" function getting called multiple times per click.
Hence it will not count by +1, but count by 1 + navigations.

On destroy and On Mount will be called, per navigation.

This bug is appearing from version 4.5.0 Onward.
I discovered it when upgrading from 4.3.7.

The latest version in which transition:persist works correctly is: 4.4.15 .
I hope this may help you

Current solution is: You have to opt out of the rerender with "transition:persist-props"

What's the expected result?

Events are only emitted once.
State is persisted.
And if component gets destroyed and rerendered, all framwork defined eventlisteners get removed.

With Astro Version 4.4.15 this problem did not occur.
Here is the example with that version: https://stackblitz.com/edit/github-xyb8rc-rruld2

Counter counts. Component trigger only one callback per click. State is persisted

Link to Minimal Reproducible Example

https://stackblitz.com/edit/github-xyb8rc

Participation

  • I am willing to submit a pull request for this issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    feat: view transitionsRelated to the View Transitions feature (scope)pkg: svelteRelated to Svelte (scope)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions