Bladeren bron

fix(runtime-vapor): invoke directive update hooks on KeepAlive reactivation

daiwei 1 maand geleden
bovenliggende
commit
a2e32e08ba

+ 4 - 0
packages/runtime-core/src/index.ts

@@ -699,3 +699,7 @@ export { knownTemplateRefs, isTemplateRefKey } from './helpers/useTemplateRef'
  * @internal
  */
 export { setCurrentRenderingInstance } from './componentRenderContext'
+/**
+ * @internal
+ */
+export { invokeDirectiveHook } from './directives'

+ 59 - 0
packages/runtime-vapor/__tests__/vdomInterop.spec.ts

@@ -2171,5 +2171,64 @@ describe('vdomInterop', () => {
       expect(beforeUpdateSpy).toHaveBeenCalledTimes(1)
       expect(updatedSpy).toHaveBeenCalledTimes(1)
     })
+
+    test('should invoke directive beforeUpdate/updated on reactivation', async () => {
+      const beforeUpdateSpy = vi.fn()
+      const updatedSpy = vi.fn()
+
+      const vDir = {
+        beforeUpdate: beforeUpdateSpy,
+        updated: updatedSpy,
+      }
+
+      const VaporChild = defineVaporComponent({
+        props: ['msg'],
+        setup(props: any) {
+          return template('<div></div>')()
+        },
+      })
+
+      const VdomChild = defineComponent({
+        setup() {
+          return () => h('span', 'vdom')
+        },
+      })
+
+      const current = shallowRef<any>(VaporChild)
+      const msg = ref('hello')
+
+      const App = defineComponent({
+        setup() {
+          return () =>
+            h(KeepAlive, null, {
+              default: () =>
+                current.value === VaporChild
+                  ? withDirectives(h(VaporChild as any, { msg: msg.value }), [
+                      [vDir],
+                    ])
+                  : h(VdomChild),
+            })
+        },
+      })
+
+      const root = document.createElement('div')
+      const app = createApp(App)
+      app.use(vaporInteropPlugin)
+      app.mount(root)
+      await nextTick()
+
+      // Deactivate vapor child
+      current.value = VdomChild
+      await nextTick()
+
+      // Change props while deactivated
+      msg.value = 'world'
+
+      // Reactivate — should trigger directive update hooks
+      current.value = VaporChild
+      await nextTick()
+      expect(beforeUpdateSpy).toHaveBeenCalledTimes(1)
+      expect(updatedSpy).toHaveBeenCalledTimes(1)
+    })
   })
 })

+ 9 - 3
packages/runtime-vapor/src/vdomInterop.ts

@@ -28,6 +28,7 @@ import {
   ensureHydrationRenderer,
   ensureRenderer,
   ensureVaporSlotFallback,
+  invokeDirectiveHook,
   isEmitListener,
   isKeepAlive,
   isVNode,
@@ -396,10 +397,12 @@ const vaporInteropImpl: Omit<
     const shouldUpdate = shouldUpdateComponent(cached, vnode)
     activate(instance, container, anchor)
     insert(vnode.anchor as any, container, anchor)
-    // in case props have changed while deactivated
-    instance.rawPropsRef!.value = filterReservedProps(vnode.props)
-    instance.rawSlotsRef!.value = vnode.children
     if (shouldUpdate) {
+      instance.rawPropsRef!.value = filterReservedProps(vnode.props)
+      instance.rawSlotsRef!.value = vnode.children
+      if (vnode.dirs) {
+        invokeDirectiveHook(vnode, cached, parentComponent, 'beforeUpdate')
+      }
       const vnodeBeforeUpdateHook =
         vnode.props && vnode.props.onVnodeBeforeUpdate
       if (vnodeBeforeUpdateHook) {
@@ -413,6 +416,9 @@ const vaporInteropImpl: Omit<
     }
     queuePostFlushCb(() => {
       if (shouldUpdate) {
+        if (vnode.dirs) {
+          invokeDirectiveHook(vnode, cached, parentComponent, 'updated')
+        }
         const vnodeUpdatedHook = vnode.props && vnode.props.onVnodeUpdated
         if (vnodeUpdatedHook) {
           callWithAsyncErrorHandling(