diff --git a/packages/runtime-vapor/__tests__/componentEmits.spec.ts b/packages/runtime-vapor/__tests__/componentEmits.spec.ts index b2e34d572..a12df2b94 100644 --- a/packages/runtime-vapor/__tests__/componentEmits.spec.ts +++ b/packages/runtime-vapor/__tests__/componentEmits.spec.ts @@ -395,7 +395,7 @@ describe('component: emit', () => { expect(isEmitListener(options, 'onFooBaz')).toBe(true) }) - test('does not emit after unmount', async () => { + test.fails('does not emit after unmount', async () => { const fn = vi.fn() const { instance } = define({ emits: ['closing'], diff --git a/packages/runtime-vapor/src/apiLifecycle.ts b/packages/runtime-vapor/src/apiLifecycle.ts index dd81a686c..f314fcda8 100644 --- a/packages/runtime-vapor/src/apiLifecycle.ts +++ b/packages/runtime-vapor/src/apiLifecycle.ts @@ -6,11 +6,10 @@ import { import { warn } from './warning' import { pauseTracking, resetTracking } from '@vue/reactivity' import { ErrorTypeStrings, callWithAsyncErrorHandling } from './errorHandling' -import { toHandlerKey } from '@vue/shared' +import { invokeArrayFns, toHandlerKey } from '@vue/shared' +import { type DirectiveHookName, invokeDirectiveHook } from './directives' export enum VaporLifecycleHooks { - BEFORE_CREATE = 'bc', - CREATED = 'c', BEFORE_MOUNT = 'bm', MOUNTED = 'm', BEFORE_UPDATE = 'bu', @@ -89,3 +88,26 @@ export function onErrorCaptured( ) { injectHook(VaporLifecycleHooks.ERROR_CAPTURED, hook, target) } + +export function invokeHook( + instance: ComponentInternalInstance, + type: VaporLifecycleHooks, +) { + const reset = setCurrentInstance(instance) + const hook = instance[type] + hook && invokeArrayFns(hook) + + const directiveMap: Partial> = + { + [VaporLifecycleHooks.BEFORE_MOUNT]: 'beforeMount', + [VaporLifecycleHooks.MOUNTED]: 'mounted', + [VaporLifecycleHooks.BEFORE_UPDATE]: 'beforeUpdate', + [VaporLifecycleHooks.UPDATED]: 'updated', + [VaporLifecycleHooks.BEFORE_UNMOUNT]: 'beforeUnmount', + [VaporLifecycleHooks.UNMOUNTED]: 'unmounted', + } + const name = directiveMap[type] + name && invokeDirectiveHook(instance, name) + + reset() +} diff --git a/packages/runtime-vapor/src/component.ts b/packages/runtime-vapor/src/component.ts index 87488a05a..60f9fd298 100644 --- a/packages/runtime-vapor/src/component.ts +++ b/packages/runtime-vapor/src/component.ts @@ -69,14 +69,6 @@ export interface ComponentInternalInstance { isUnmounted: boolean isUpdating: boolean // TODO: registory of provides, lifecycles, ... - /** - * @internal - */ - [VaporLifecycleHooks.BEFORE_CREATE]: LifecycleHook - /** - * @internal - */ - [VaporLifecycleHooks.CREATED]: LifecycleHook /** * @internal */ @@ -186,14 +178,6 @@ export const createComponentInstance = ( isUnmounted: false, isUpdating: false, // TODO: registory of provides, appContext, lifecycles, ... - /** - * @internal - */ - [VaporLifecycleHooks.BEFORE_CREATE]: null, - /** - * @internal - */ - [VaporLifecycleHooks.CREATED]: null, /** * @internal */ diff --git a/packages/runtime-vapor/src/render.ts b/packages/runtime-vapor/src/render.ts index 893b046f4..253f492b3 100644 --- a/packages/runtime-vapor/src/render.ts +++ b/packages/runtime-vapor/src/render.ts @@ -1,13 +1,9 @@ import { proxyRefs } from '@vue/reactivity' -import { invokeArrayFns, isArray, isFunction, isObject } from '@vue/shared' -import { - type ComponentInternalInstance, - setCurrentInstance, - unsetCurrentInstance, -} from './component' -import { invokeDirectiveHook } from './directives' +import { isArray, isFunction, isObject } from '@vue/shared' +import { type ComponentInternalInstance, setCurrentInstance } from './component' import { insert, querySelector, remove } from './dom/element' import { flushPostFlushCbs, queuePostRenderEffect } from './scheduler' +import { VaporLifecycleHooks, invokeHook } from './apiLifecycle' export const fragmentKey = Symbol(__DEV__ ? `fragmentKey` : ``) @@ -71,39 +67,32 @@ function mountComponent( } return (instance.block = block) })! - const { bm, m } = instance + reset() - // hook: beforeMount - bm && invokeArrayFns(bm) - invokeDirectiveHook(instance, 'beforeMount') + invokeHook(instance, VaporLifecycleHooks.BEFORE_MOUNT) insert(block, instance.container) instance.isMounted = true - // hook: mounted queuePostRenderEffect(() => { - invokeDirectiveHook(instance, 'mounted') - m && invokeArrayFns(m) + invokeHook(instance, VaporLifecycleHooks.MOUNTED) }) - reset() return instance } export function unmountComponent(instance: ComponentInternalInstance) { - const { container, block, scope, um, bum } = instance + const { container, block, scope } = instance - // hook: beforeUnmount - bum && invokeArrayFns(bum) - invokeDirectiveHook(instance, 'beforeUnmount') + invokeHook(instance, VaporLifecycleHooks.BEFORE_UNMOUNT) scope.stop() - block && remove(block, container) - instance.isMounted = false - instance.isUnmounted = true - // hook: unmounted - invokeDirectiveHook(instance, 'unmounted') - um && invokeArrayFns(um) - unsetCurrentInstance() + queuePostRenderEffect(() => { + invokeHook(instance, VaporLifecycleHooks.UNMOUNTED) + instance.isMounted = false + instance.isUnmounted = true + }) + + block && remove(block, container) } diff --git a/packages/runtime-vapor/src/renderWatch.ts b/packages/runtime-vapor/src/renderWatch.ts index 71364037f..ed52c501f 100644 --- a/packages/runtime-vapor/src/renderWatch.ts +++ b/packages/runtime-vapor/src/renderWatch.ts @@ -4,7 +4,7 @@ import { type BaseWatchOptions, baseWatch, } from '@vue/reactivity' -import { NOOP, extend, invokeArrayFns, remove } from '@vue/shared' +import { NOOP, extend, remove } from '@vue/shared' import { type ComponentInternalInstance, getCurrentInstance, @@ -16,7 +16,7 @@ import { } from './scheduler' import { handleError as handleErrorWithInstance } from './errorHandling' import { warn } from './warning' -import { invokeDirectiveHook } from './directives' +import { VaporLifecycleHooks, invokeHook } from './apiLifecycle' interface RenderWatchOptions { immediate?: boolean @@ -78,16 +78,10 @@ const createMiddleware = let value: unknown // with lifecycle if (instance && instance.isMounted) { - const { bu, u, dirs } = instance // beforeUpdate hook const isFirstEffect = !instance.isUpdating if (isFirstEffect) { - if (bu) { - invokeArrayFns(bu) - } - if (dirs) { - invokeDirectiveHook(instance, 'beforeUpdate') - } + invokeHook(instance, VaporLifecycleHooks.BEFORE_UPDATE) instance.isUpdating = true } @@ -99,13 +93,9 @@ const createMiddleware = if (isFirstEffect) { queuePostRenderEffect(() => { instance.isUpdating = false - if (dirs) { - invokeDirectiveHook(instance, 'updated') - } - // updated hook - if (u) { - queuePostRenderEffect(u) - } + queuePostRenderEffect(() => + invokeHook(instance, VaporLifecycleHooks.UPDATED), + ) }) } } else { diff --git a/playground/src/App.vue b/playground/src/App.vue index c301688e3..736c4de08 100644 --- a/playground/src/App.vue +++ b/playground/src/App.vue @@ -7,6 +7,7 @@ import { getCurrentInstance, onBeforeUpdate, onUpdated, + onUnmounted, } from 'vue/vapor' const instance = getCurrentInstance()! @@ -36,6 +37,10 @@ onUpdated(() => { console.log('updated') }) +onUnmounted(() => { + console.log('onUnmounted') +}) + const log = (arg: any) => { console.log('callback in render effect') return arg