Subscribe on changes!

keep-alive vnode缓存与shapeFlag不一致导致组件切换路由被销毁的问题

avatar
Jan 6th 2022

Version

3.2.26

Reproduction link

http://github.com/

Steps to reproduce

        <router-view v-slot="{ Component }">
            <transition name="fade-transform" mode="out-in">
                <keep-alive :include="cachedViews">
                    <component :is="Component" />
                </keep-alive>
            </transition>
        </router-view>

重现

  • 初始状态cachedViews为[]
  • component mounted之后,改变cachedViews的值,使component命中cachedViews,component的vnode会被缓存到 cache中,但是返回的vnode的shapeFlag是4,没有被标记为COMPONENT_SHOULD_KEEP_ALIVE(260)
  • 切换路由,component被销毁,isUnmounted: true
  • 再次切换回路由回来,会命中keep-alive的缓存,返回缓存的vnode,由于vnode对应的组件被销毁,导致组件会假死失去响应。

可能原因

      // 289行
      // 当组件mounted之后update就会将vnode拷贝一份
      // clone vnode if it's reused because we are going to mutate it
      if (vnode.el) {
        vnode = cloneVNode(vnode)
        if (rawVNode.shapeFlag & ShapeFlags.SUSPENSE) {
          rawVNode.ssContent = vnode
        }
      }
  
      // 322行
      // 改变了拷贝的vnode的shapeFlag为KEEP_ALIVE,但是返回的是rawVNode   
      // rawVNode的shapeFlag还是4
      // avoid vnode being unmounted
      vnode.shapeFlag |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE

      current = vnode
      return rawVNode

What is expected?

组件mounted之后命中include能正确被缓存。

What is actually happening?

组件mounted之后命中include能被缓存,切换路由时组件会被销毁,重新激活时组件假死。

avatar
Jan 7th 2022

maybe it's a duplicate of https://github.com/vuejs/vue-next/issues/4984 /cc @ygj6

avatar
Jan 7th 2022

@edison1105 确实和 #4984 差不多的问题,用你的方法解决了,感谢!

<script lang="ts">
import { defineComponent,computed } from 'vue'
import { useStore } from 'vuex'

export default defineComponent({
    name: 'AppMain',
    setup() {
        const store = useStore();

        const cachedViews = computed(() => [...store.getters.cachedViews])

        return {
            cachedViews
        }
    },
})
</script>

展开数组后transition组件能响应数组项变化了,当cacheViews push、splice时 ,update从keep-alive组件提升到了transition组件,从父组件更新时会更新插槽生成新的component vnode,问题得到解决!

avatar
Jan 12th 2022

我的还是不行啊...

avatar
Jan 12th 2022

我的还是不行啊...

你是和我一样的问题么,展开cachedView之后我的缓存正常了。

avatar
Jan 13th 2022

不行啊

<template> <el-main> <router-view v-slot="{ Component }"> <keep-alive :include="cacheViews"> <component :is="Component" /> </keep-alive> </router-view> </el-main> </template>

`

我这个不在App.vue中 应该跟它没关系把 store里面Name都有的啊

大佬瞅瞅? `

avatar
Jan 13th 2022
       <router-view v-slot="{ Component }">
            <transition name="fade-transform" mode="out-in">
                <keep-alive :include="cachedViews">
                    <component :is="Component" />
                </keep-alive>
            </transition>
        </router-view>
<script lang="ts">
import { defineComponent,computed } from 'vue'
import { useStore } from 'vuex'

export default defineComponent({
    name: 'AppMain',
    setup() {
        const store = useStore();

        // 这里绑定的值要展开为新的数组, 这里你展开了么?
        const cachedViews = computed(() => [...store.getters.cachedViews])

        return {
            cachedViews
        }
    },
})
</script>
avatar
Jan 13th 2022

image 我是在这里展开的 但是没用...

avatar
Jan 13th 2022

image 我是在这里展开的 但是没用...

暂时不知道你这个是什么情况,我试了一下即使去掉transaction组件和你一样,我这个也是正常的。按原理来说只要提示组件的更新到上一级就可以的,这是我的代码

avatar
Jan 13th 2022

@AK47-dadada 传个简单的可以复现的 demo 吧。

avatar
Jan 13th 2022

image 我是在这里展开的 但是没用...

暂时不知道你这个是什么情况,我试了一下即使去掉transaction组件和你一样,我这个也是正常的。按原理来说只要提示组件的更新到上一级就可以的,这是我的代码

我确实不知道影响元素是哪个,很伤脑筋

avatar
Jan 13th 2022

@edison1105 大佬你稍等,我想想办法给你个demo

avatar
Jan 13th 2022

image 我是在这里展开的 但是没用...

暂时不知道你这个是什么情况,我试了一下即使去掉transaction组件和你一样,我这个也是正常的。按原理来说只要提示组件的更新到上一级就可以的,这是我的代码

我确实不知道影响元素是哪个,很伤脑筋

你发个demo出来让edison大佬给你看看。

avatar
Jan 13th 2022

@qq10137383 没玩过这种线上的demo,而且我的跟你的这种差不多,可能会比较麻烦.... 正在想办法给他搞demo

avatar
Jan 13th 2022

@qq10137383 搞了个线上demo居然没问题................................................................................................................................................ https://codesandbox.io/s/withered-fire-h2c35?file=/src/App.vue

avatar
Jan 13th 2022

How can you call yourself ak47? Are you trying to be cute or jus downright stupid?

On Jan 12, 2022, at 7:40 PM, AK47-dadada @.***> wrote:

 @qq10137383 搞了个线上demo居然没问题................................................................................................................................................

— Reply to this email directly, view it on GitHub, or unsubscribe. Triage notifications on the go with GitHub Mobile for iOS or Android. You are receiving this because you are subscribed to this thread.

avatar
Jan 13th 2022

@edison1105 这里有人骂人嗷

avatar
Jan 13th 2022

How can you call yourself ak47? Are you trying to be cute or jus downright stupid? On Jan 12, 2022, at 7:40 PM, AK47-dadada @.***> wrote:  @qq10137383 搞了个线上demo居然没问题................................................................................................................................................ — Reply to this email directly, view it on GitHub, or unsubscribe. Triage notifications on the go with GitHub Mobile for iOS or Android. You are receiving this because you are subscribed to this thread.

It's just a username. Don't make people think you're jus downright stupid

avatar
Jan 13th 2022

@yyx990803 尤大 这里有人骂人哦

avatar
Jan 17th 2022

@qq10137383 兄弟 问题得到解决了 @edison1105 大佬,这个可以参照一下 http://www.jmblog.com.cn/article/61e5471af3e068311c322440

avatar
Jan 17th 2022

@qq10137383 兄弟 问题得到解决了 @edison1105 大佬,这个可以参照一下 http://www.jmblog.com.cn/article/61e5471af3e068311c322440

子路由的<router-view/>,也要单独加keepalive,这跟vue2的keepalive是一致的。