Nested components in detached branch render while being detached
Version
3.2.31
Reproduction link
Steps to reproduce
- Click on Show Async
- Wait for everything to be displayed, then click Show Sync
- Click Show Async
- Wait for everything to be displayed, then click once again on Show Sync
What is expected?
- The async child should render only once in the first click
- One should be able to switch back and forth
What is actually happening?
- The first toggle causes the async child to render twice
- After two toggles, the application completely crashes
I have a few errors that seem to be related and I'm struggling to find a better way of doing things. Currently, the router renders nested routes by providing an incrementing depth. But this causes situations like:
- https://github.com/vuejs/router/issues/626#issuecomment-736355520
- https://github.com/vuejs/router/issues/1324
- https://github.com/vuejs/router/issues/1319
The problem is that while the route changes and triggers an update in the root router view component, in some of these scenarios (like Suspense and Keep alive), the nested router views manage to render (or at least call their render function) once before the parent actually tries to render itself, making them mount a nested component of a different route to be immediately discarded or never used. Then the root router view renders the correct page and its nested router view renders the correct view too. This doesn't happen in plain <router-view>
usage. I tried a few solutions to this. I even tried creating a shallow ref inside the root RouterView, that is provided to its children and that only changes after the navigation has finished but this encounters race issues and is overall flaky.
Made this that could probably be a solution: https://github.com/vuejs/core/pull/6736
Any updates on this issue? Would be great if we can just use page transitions without having to worry about redirecting too fast.. (https://github.com/nuxt/nuxt/issues/13350)
I checked reproduction in the description with vue v3.3.0-beta.1. I added prop suspensible
to <suspense>
in ParentAsync.vue
. Still, there was two mounts of async child.
See https://play.vuejs.org/
PS. If you add suspensible
option in ParentSync.vue
, there is an error suspense.resolve() is called without a pending branch.