Skip to content

Commit

Permalink
fix(runtime-core): should run vnode hook with component (vuejs#684)
Browse files Browse the repository at this point in the history
  • Loading branch information
underfin committed Feb 4, 2020
1 parent a9f3cad commit 44a9ccf
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 2 deletions.
79 changes: 79 additions & 0 deletions packages/runtime-core/__tests__/renderVnodeHook.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { h } from '../src/h'
import { nextTick, nodeOps, ref, render } from '@vue/runtime-test'

describe('renderer: vnode hook', () => {
test('element', async () => {
const onVnodeBeforeMount = jest.fn()
const onVnodeMounted = jest.fn()
const onVnodeBeforeUpdate = jest.fn()
const onVnodeUpdated = jest.fn()
const onVnodeBeforeUnmount = jest.fn()
const onVnodeUnmounted = jest.fn()
const root = nodeOps.createElement('div')
const count = ref(0)

const App = () =>
h('div', {
onVnodeBeforeMount,
onVnodeMounted,
onVnodeBeforeUpdate,
onVnodeUpdated,
onVnodeBeforeUnmount,
onVnodeUnmounted,
count: count.value
})

render(h(App), root)
await nextTick()
expect(onVnodeBeforeMount).toBeCalled()
expect(onVnodeMounted).toBeCalled()

count.value++
await nextTick()
expect(onVnodeBeforeUpdate).toBeCalled()
expect(onVnodeUpdated).toBeCalled()

render(null, root)
await nextTick()
expect(onVnodeBeforeUnmount).toBeCalled()
expect(onVnodeUnmounted).toBeCalled()
})

test('component', async () => {
const Comp = () => h('div')
const onVnodeBeforeMount = jest.fn()
const onVnodeMounted = jest.fn()
const onVnodeBeforeUpdate = jest.fn()
const onVnodeUpdated = jest.fn()
const onVnodeBeforeUnmount = jest.fn()
const onVnodeUnmounted = jest.fn()
const root = nodeOps.createElement('div')
const count = ref(0)

const App = () =>
h(Comp, {
onVnodeBeforeMount,
onVnodeMounted,
onVnodeBeforeUpdate,
onVnodeUpdated,
onVnodeBeforeUnmount,
onVnodeUnmounted,
count: count.value
})

render(h(App), root)
await nextTick()
expect(onVnodeBeforeMount).toBeCalled()
expect(onVnodeMounted).toBeCalled()

count.value++
await nextTick()
expect(onVnodeBeforeUpdate).toBeCalled()
expect(onVnodeUpdated).toBeCalled()

render(null, root)
await nextTick()
expect(onVnodeBeforeUnmount).toBeCalled()
expect(onVnodeUnmounted).toBeCalled()
})
})
2 changes: 2 additions & 0 deletions packages/runtime-core/src/components/Suspense.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ export interface SuspenseBoundary<
setupRenderEffect: (
instance: ComponentInternalInstance,
parentSuspense: SuspenseBoundary<HostNode, HostElement> | null,
parentComponent: ComponentInternalInstance | null,
initialVNode: VNode<HostNode, HostElement>,
container: HostElement,
anchor: HostNode | null,
Expand Down Expand Up @@ -420,6 +421,7 @@ function createSuspenseBoundary<HostNode, HostElement>(
setupRenderEffect(
instance,
suspense,
parentComponent,
vnode,
// component may have been moved before resolve
parentNode(instance.subTree.el)!,
Expand Down
62 changes: 60 additions & 2 deletions packages/runtime-core/src/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,7 @@ export function createRenderer<
setupRenderEffect(
instance,
parentSuspense,
parentComponent,
initialVNode,
container,
anchor,
Expand All @@ -984,6 +985,7 @@ export function createRenderer<
function setupRenderEffect(
instance: ComponentInternalInstance,
parentSuspense: HostSuspenseBoundary | null,
parentComponent: ComponentInternalInstance | null,
initialVNode: HostVNode,
container: HostElement,
anchor: HostNode | null,
Expand All @@ -993,16 +995,29 @@ export function createRenderer<
instance.update = effect(function componentEffect() {
if (!instance.isMounted) {
const subTree = (instance.subTree = renderComponentRoot(instance))
const { props } = instance.vnode
// beforeMount hook
if (instance.bm !== null) {
invokeHooks(instance.bm)
}
if (props && props.onVnodeBeforeMount != null) {
invokeDirectiveHook(
props.onVnodeBeforeMount,
parentComponent,
subTree
)
}
patch(null, subTree, container, anchor, instance, parentSuspense, isSVG)
initialVNode.el = subTree.el
// mounted hook
if (instance.m !== null) {
queuePostRenderEffect(instance.m, parentSuspense)
}
if (props && props.onVnodeMounted != null) {
queuePostRenderEffect(() => {
invokeDirectiveHook(props.onVnodeMounted!, parentComponent, subTree)
}, parentSuspense)
}
// activated hook for keep-alive roots.
if (
instance.a !== null &&
Expand All @@ -1016,6 +1031,7 @@ export function createRenderer<
// This is triggered by mutation of component's own state (next: null)
// OR parent calling processComponent (next: HostVNode)
const { next } = instance
const { props } = instance.vnode

if (__DEV__) {
pushWarningContext(next || instance.vnode)
Expand All @@ -1031,6 +1047,14 @@ export function createRenderer<
if (instance.bu !== null) {
invokeHooks(instance.bu)
}
if (props && props.onVnodeBeforeUpdate != null) {
invokeDirectiveHook(
props.onVnodeBeforeUpdate,
parentComponent,
nextTree,
prevTree
)
}
// reset refs
// only needed if previous patch had refs
if (instance.refs !== EMPTY_OBJ) {
Expand Down Expand Up @@ -1058,6 +1082,16 @@ export function createRenderer<
if (instance.u !== null) {
queuePostRenderEffect(instance.u, parentSuspense)
}
if (props && props.onVnodeUpdated != null) {
queuePostRenderEffect(() => {
invokeDirectiveHook(
props.onVnodeUpdated!,
parentComponent,
nextTree,
prevTree
)
}, parentSuspense)
}

if (__DEV__) {
popWarningContext()
Expand Down Expand Up @@ -1539,7 +1573,12 @@ export function createRenderer<
if (shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) {
;(parentComponent!.sink as KeepAliveSink).deactivate(vnode)
} else {
unmountComponent(vnode.component!, parentSuspense, doRemove)
unmountComponent(
vnode.component!,
parentSuspense,
parentComponent,
doRemove
)
}
return
}
Expand Down Expand Up @@ -1621,17 +1660,31 @@ export function createRenderer<
function unmountComponent(
instance: ComponentInternalInstance,
parentSuspense: HostSuspenseBoundary | null,
parentComponent: ComponentInternalInstance | null,
doRemove?: boolean
) {
if (__HMR__ && instance.type.__hmrId != null) {
unregisterHMR(instance)
}

const { bum, effects, update, subTree, um, da, isDeactivated } = instance
const {
bum,
effects,
update,
subTree,
um,
da,
isDeactivated,
vnode
} = instance
const { props } = vnode
// beforeUnmount hook
if (bum !== null) {
invokeHooks(bum)
}
if (props && props.onVnodeBeforeUnmount != null) {
invokeDirectiveHook(props.onVnodeBeforeUnmount, parentComponent, subTree)
}
if (effects !== null) {
for (let i = 0; i < effects.length; i++) {
stop(effects[i])
Expand All @@ -1647,6 +1700,11 @@ export function createRenderer<
if (um !== null) {
queuePostRenderEffect(um, parentSuspense)
}
if (props && props.onVnodeUnmounted != null) {
queuePostRenderEffect(() => {
invokeDirectiveHook(props.onVnodeUnmounted!, parentComponent, subTree)
}, parentSuspense)
}
// deactivated hook
if (
da !== null &&
Expand Down

0 comments on commit 44a9ccf

Please sign in to comment.