Skip to content

Using pageTransition/layoutTransition and useAsyncData() leads to faulty double-mounting #32371

@exophunk

Description

@exophunk

Environment

  • Operating System: Darwin
  • Node Version: v20.17.0
  • Nuxt Version: 3.17.5
  • CLI Version: 3.25.1
  • Nitro Version: 2.11.12
  • Package Manager: npm@11.4.1
  • Builder: -
  • User Config: compatibilityDate, devtools, ssr, app
  • Runtime Modules: -
  • Build Modules: -

Reproduction

https://stackblitz.com/github/exophunk/nuxt-doublemounted-issue
https://github.com/exophunk/nuxt-doublemounted-issue
The reproduction shows various circumstances where that issue happens. Details are described in the reproduction index page.

Steps:

  1. Switch between the different page examples
  2. See console.log() for onMounted() logging twice!

Describe the bug

Whenever you are using pageTransition or layoutTransition in your app, the usage of any async function inside the <setup> part of a page (or any child component) leads to faulty mounting the page twice!

As const { data } = await useFetch('...'); is a very common in setup, the chances of this issue to happen is quite common. Whenever you have this on combination with transitions, mounting happens twice.

  1. Layout Transitions

    • Using Layout Transitions: layoutTransition: { mode: 'out-in', name: 'page', duration: 300 }
    • Using any async method in setup of pages or child components
  2. Page Transitions

    • Using Page Transitions: pageTransition: { mode: 'out-in', name: 'page', duration: 300 }
    • Using NESTED parent/child pages (for page transition, it only happens with nesting)
    • Using any async method in setup of pages or child components
  • Using any async method causes the issue (useFetch, useAsyncData, or any other method with await)
  • Not a SSR issue, happens on client-only too

What is the problem?

Mounting a page twice (and mounting every child component twice) can lead to various unexpected bugs, especially for UI components that init themselves on mount or components that perform any idempotent actions or API calls. This can be very severe! In our case, a ecommerce checkout call was sent twice to the backend! And it was hard to spot or figure out why. Noone expects onMounted() to happen twice.

Quick fix workaround

To fix the issue, you can wrap <NuxtPage /> inside a <Suspense>.

<Suspense>
    <NuxtPage />
</Suspense>

The Suspense Quick Fix seems to work fine. We have it in production now for about half a year. But I can't say if it has any drawbacks or creates issues elsewhere. It's also difficult to make sure our devs know of this workaround and do not create new pages without it.

Additional context

The issue was once further explained as a comment to #27364. The bug is open for +1 Year now.

I updated the reproduction to 3.17.5 and the bug persists.
I suggest closing the other, less clearly described issue and keep tracking this one.

If it's not an easy fix, then I would suggest that after 1 year, at least a warning in the documentation should be placed that page/layout transitions should be used with caution.

Related:
nuxt/scripts#297
#27442
#27364

Metadata

Metadata

Assignees

No one assigned

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions