vuejs / core

🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
https://vuejs.org/
MIT License
47.71k stars 8.34k forks source link

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

Closed qq10137383 closed 2 years ago

qq10137383 commented 2 years ago

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>

重现

可能原因

      // 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能被缓存,切换路由时组件会被销毁,重新激活时组件假死。

edison1105 commented 2 years ago

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

qq10137383 commented 2 years ago

@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,问题得到解决!

AK47-dadada commented 2 years ago

我的还是不行啊...

qq10137383 commented 2 years ago

我的还是不行啊...

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

AK47-dadada commented 2 years ago

不行啊

`

`

`

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

大佬瞅瞅? `

qq10137383 commented 2 years ago
<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
    }
},

})

AK47-dadada commented 2 years ago

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

qq10137383 commented 2 years ago

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

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

edison1105 commented 2 years ago

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

AK47-dadada commented 2 years ago

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

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

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

AK47-dadada commented 2 years ago

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

qq10137383 commented 2 years ago

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

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

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

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

AK47-dadada commented 2 years ago

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

AK47-dadada commented 2 years ago

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

Codermar commented 2 years ago

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.

AK47-dadada commented 2 years ago

@edison1105 这里有人骂人嗷

AK47-dadada commented 2 years ago

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

AK47-dadada commented 2 years ago

@yyx990803 尤大 这里有人骂人哦

AK47-dadada commented 2 years ago

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

edison1105 commented 2 years ago

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

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