vuejs / router

🚦 The official router for Vue.js
https://router.vuejs.org/
MIT License
3.88k stars 1.18k forks source link

When using nested RouterView and KeepAlive, components aren't detached properly #2314

Closed CrimsonFez closed 2 months ago

CrimsonFez commented 2 months ago

Reproduction

https://github.com/CrimsonFez/vuejs-keep-alive-router-bug/

Steps to reproduce the bug

You need to have nested RouterView + KeepAlives like:

App.vue

<RouterView>
  <KeepAlive>
    <Component>

MyLayoutAndGetter1.vue

<RouterView>
  <KeepAlive>
    <Component :my-object="my-object">

MyLayoutAndGetter2.vue

<RouterView>
  <KeepAlive>
    <Component :my-object="my-object">

I believe that you also need to pass props through one of the router views, see https://github.com/CrimsonFez/vuejs-keep-alive-router-bug/blob/main/src/views/Person.vue

See my linked repo for full reproduction.

Expected behavior

This should behave like normal, when KeepAlive is not used

Actual behavior

When changing from one nested routerview to the other, it looks like props from the old router view are temporarily attached to the new router view

[Vue warn]: Missing required prop: "region" 
  at <RegionAbout onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< null > person= 
Object { id: "gandalf", name: "Gandalf", summary: "2000 year old pot smoking wizard" }
  ... > 
  at <KeepAlive key=0 > 
  at <RouterView key=0 > 
  at <Person personId="gandalf" onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< null >  ... > 
  at <KeepAlive key=0 > 
  at <RouterView> 
  at <App>

In my reproduction, this just causes an error, but on my larger app, this causes a crash.

Additional information

No response

CrimsonFez commented 2 months ago

For anyone else with this issue, I found a work around. Give the 2nd level routerviews each a unique name, then in router.ts set that as the view for your child components.

posva commented 2 months ago

Duplicate of #626

posva commented 2 months ago

Some of this behavior is inherent to KeepAlive and how it keeps updating components that are kept alive. Check this Vue playground to give you an idea of the behavior: