diff --git a/packages/runtime-core/__tests__/hydration.spec.ts b/packages/runtime-core/__tests__/hydration.spec.ts index fa89631d201..0114e41e505 100644 --- a/packages/runtime-core/__tests__/hydration.spec.ts +++ b/packages/runtime-core/__tests__/hydration.spec.ts @@ -699,4 +699,44 @@ describe('SSR hydration', () => { expect(`Hydration children mismatch`).toHaveBeenWarned() }) }) + + test('sets and removes internal hydration flag', async () => { + const checkHydration = jest.fn() + + const container = document.createElement('div') + container.innerHTML = '
foo
' + + const visible = ref(true) + const component = defineComponent({ + render: () => h('div', 'foo'), + created() { + checkHydration(this.$.isHydrating) + }, + beforeMount() { + checkHydration(this.$.isHydrating) + }, + mounted() { + checkHydration(this.$.isHydrating) + } + }) + const app = createSSRApp({ + render: () => (visible.value ? h(component) : null) + }) + + app.mount(container) + + visible.value = false + await nextTick() + visible.value = true + await nextTick() + + expect(checkHydration.mock.calls).toMatchObject([ + [true], + [true], + [true], + [false], + [false], + [false] + ]) + }) }) diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index 0bc928911e5..5a8461d6ad7 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -297,6 +297,7 @@ export interface ComponentInternalInstance { isMounted: boolean isUnmounted: boolean isDeactivated: boolean + isHydrating: boolean /** * @internal */ @@ -407,6 +408,7 @@ export function createComponentInstance( isMounted: false, isUnmounted: false, isDeactivated: false, + isHydrating: false, bc: null, c: null, bm: null, diff --git a/packages/runtime-core/src/hydration.ts b/packages/runtime-core/src/hydration.ts index c2d13a1986d..c9cf6953d0d 100644 --- a/packages/runtime-core/src/hydration.ts +++ b/packages/runtime-core/src/hydration.ts @@ -180,7 +180,8 @@ export function createHydrationFunctions( parentComponent, parentSuspense, isSVGContainer(container), - optimized + optimized, + true ) } // async component diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index cae1ffe57c1..1b767979f9a 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -232,7 +232,8 @@ export type MountComponentFn = ( parentComponent: ComponentInternalInstance | null, parentSuspense: SuspenseBoundary | null, isSVG: boolean, - optimized: boolean + optimized: boolean, + hydrating?: boolean ) => void type ProcessTextOrCommentFn = ( @@ -1178,7 +1179,8 @@ function baseCreateRenderer( parentComponent, parentSuspense, isSVG, - optimized + optimized, + hydrating = false ) => { const instance: ComponentInternalInstance = (initialVNode.component = createComponentInstance( initialVNode, @@ -1186,6 +1188,8 @@ function baseCreateRenderer( parentSuspense )) + instance.isHydrating = hydrating + if (__DEV__ && instance.type.__hmrId) { registerHMR(instance) } @@ -1352,6 +1356,7 @@ function baseCreateRenderer( if ((vnodeHook = props && props.onVnodeMounted)) { queuePostRenderEffect(() => { invokeVNodeHook(vnodeHook!, parent, initialVNode) + instance.isHydrating = false }, parentSuspense) } // activated hook for keep-alive roots.