]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(keep-alive): invoke initial activated hook for async components
authorEvan You <yyx990803@gmail.com>
Thu, 12 May 2022 03:29:26 +0000 (11:29 +0800)
committerEvan You <yyx990803@gmail.com>
Thu, 12 May 2022 03:29:26 +0000 (11:29 +0800)
revert #5459
fix #5095
fix #5651

packages/runtime-core/__tests__/apiAsyncComponent.spec.ts
packages/runtime-core/src/apiAsyncComponent.ts
packages/runtime-core/src/renderer.ts

index c9ab33ce9179c55d1d42fb2ba2542665af1a1ac0..45b82923dbab0981328d675dc564b97853d047b8 100644 (file)
@@ -802,7 +802,7 @@ describe('api: defineAsyncComponent', () => {
     expect(vnodeHooks.onVnodeUnmounted).toHaveBeenCalledTimes(1)
   })
 
-  test('with keepalive', async () => {
+  test('with KeepAlive', async () => {
     const spy = jest.fn()
     let resolve: (comp: Component) => void
 
@@ -813,9 +813,12 @@ describe('api: defineAsyncComponent', () => {
         })
     )
 
+    const Bar = defineAsyncComponent(() => Promise.resolve(() => 'Bar'))
+
+    const toggle = ref(true)
     const root = nodeOps.createElement('div')
     const app = createApp({
-      render: () => h(KeepAlive, [h(Foo)])
+      render: () => h(KeepAlive, [toggle.value ? h(Foo) : h(Bar)])
     })
 
     app.mount(root)
@@ -826,13 +829,16 @@ describe('api: defineAsyncComponent', () => {
         onActivated(() => {
           spy()
         })
-        return () => 'resolved'
+        return () => 'Foo'
       }
     })
 
     await timeout()
-    expect(serializeInner(root)).toBe('resolved')
+    expect(serializeInner(root)).toBe('Foo')
     expect(spy).toBeCalledTimes(1)
-  })
 
+    toggle.value = false
+    await timeout()
+    expect(serializeInner(root)).toBe('Bar')
+  })
 })
index 957aa0bb5f087f5cb44b990e290e0f419b6436b5..c9b96607b5f39082f04ee4e4924bc6e53ffa36de 100644 (file)
@@ -6,7 +6,7 @@ import {
   isInSSRComponentSetup,
   ComponentOptions
 } from './component'
-import { isFunction, isObject, ShapeFlags } from '@vue/shared'
+import { isFunction, isObject } from '@vue/shared'
 import { ComponentPublicInstance } from './componentPublicInstance'
 import { createVNode, VNode } from './vnode'
 import { defineComponent } from './apiDefineComponent'
@@ -211,14 +211,13 @@ export function defineAsyncComponent<
 
 function createInnerComp(
   comp: ConcreteComponent,
-  { vnode: { ref, props, children }, parent }: ComponentInternalInstance
+  {
+    vnode: { ref, props, children, shapeFlag },
+    parent
+  }: ComponentInternalInstance
 ) {
   const vnode = createVNode(comp, props, children)
   // ensure inner component inherits the async wrapper's ref owner
   vnode.ref = ref
-  
-  if (parent && isKeepAlive(parent.vnode)) {
-    vnode.shapeFlag |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE
-  }
   return vnode
 }
index bd4a03e87c1ec7c885aa46fd95905d581be2c35b..8af783a20c9f6f05d3329f01852bcec9de4b81e8 100644 (file)
@@ -1420,7 +1420,12 @@ function baseCreateRenderer(
         // activated hook for keep-alive roots.
         // #1742 activated hook must be accessed after first render
         // since the hook may be injected by a child keep-alive
-        if (initialVNode.shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) {
+        if (
+          initialVNode.shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE ||
+          (parent &&
+            isAsyncWrapper(parent.vnode) &&
+            parent.vnode.shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE)
+        ) {
           instance.a && queuePostRenderEffect(instance.a, parentSuspense)
           if (
             __COMPAT__ &&