Skip to content

feat(runtime-vapor): lifecycle hooks of dynamic sub-components #258

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 65 additions & 39 deletions packages/runtime-vapor/__tests__/apiLifecycle.spec.ts
Original file line number Diff line number Diff line change
@@ -136,7 +136,7 @@ describe('api: lifecycle hooks', () => {
it('onBeforeUnmount', async () => {
const toggle = ref(true)
const fn = vi.fn(() => {
expect(host.innerHTML).toBe('<div></div>')
expect(host.innerHTML).toBe('<div></div><!--if-->')
})
const { render, host } = define({
setup() {
@@ -165,14 +165,14 @@ describe('api: lifecycle hooks', () => {

toggle.value = false
await nextTick()
// expect(fn).toHaveBeenCalledTimes(1) // FIXME: not called
expect(fn).toHaveBeenCalledTimes(1)
expect(host.innerHTML).toBe('<!--if-->')
})

it('onUnmounted', async () => {
const toggle = ref(true)
const fn = vi.fn(() => {
expect(host.innerHTML).toBe('<div></div>')
expect(host.innerHTML).toBe('<!--if-->')
})
const { render, host } = define({
setup() {
@@ -201,14 +201,14 @@ describe('api: lifecycle hooks', () => {

toggle.value = false
await nextTick()
// expect(fn).toHaveBeenCalledTimes(1) // FIXME: not called
expect(fn).toHaveBeenCalledTimes(1)
expect(host.innerHTML).toBe('<!--if-->')
})

it('onBeforeUnmount in onMounted', async () => {
const toggle = ref(true)
const fn = vi.fn(() => {
expect(host.innerHTML).toBe('<div></div>')
expect(host.innerHTML).toBe('<div></div><!--if-->')
})
const { render, host } = define({
setup() {
@@ -239,29 +239,32 @@ describe('api: lifecycle hooks', () => {

toggle.value = false
await nextTick()
// expect(fn).toHaveBeenCalledTimes(1) // FIXME: not called
expect(fn).toHaveBeenCalledTimes(1)
expect(host.innerHTML).toBe('<!--if-->')
})

it('lifecycle call order', async () => {
const count = ref(0)
const rootCounter = ref(0)
const propsCounter = ref(0)
const toggle = ref(true)
const calls: string[] = []

const { render } = define({
setup() {
onBeforeMount(() => calls.push('onBeforeMount'))
onMounted(() => calls.push('onMounted'))
onBeforeUpdate(() => calls.push('onBeforeUpdate'))
onUpdated(() => calls.push('onUpdated'))
onBeforeUnmount(() => calls.push('onBeforeUnmount'))
onUnmounted(() => calls.push('onUnmounted'))
onBeforeMount(() => calls.push('root onBeforeMount'))
onMounted(() => calls.push('root onMounted'))
onBeforeUpdate(() => calls.push('root onBeforeUpdate'))
onUpdated(() => calls.push('root onUpdated'))
onBeforeUnmount(() => calls.push('root onBeforeUnmount'))
onUnmounted(() => calls.push('root onUnmounted'))
return (() => {
const n0 = createIf(
const n0 = template('<p></p>')()
renderEffect(() => setText(n0, rootCounter.value))
const n1 = createIf(
() => toggle.value,
() => createComponent(Mid, { count: () => count.value }),
() => createComponent(Mid, { count: () => propsCounter.value }),
)
return n0
return [n0, n1]
})()
},
})
@@ -303,42 +306,65 @@ describe('api: lifecycle hooks', () => {
// mount
render()
expect(calls).toEqual([
'onBeforeMount',
'root onBeforeMount',
'mid onBeforeMount',
'child onBeforeMount',
'child onMounted',
'mid onMounted',
'onMounted',
'root onMounted',
])

calls.length = 0

// update
count.value++
// props update
propsCounter.value++
await nextTick()
// There are no calls in the root and mid,
// but maybe such performance would be better.
expect(calls).toEqual([
// 'root onBeforeUpdate',
// 'mid onBeforeUpdate',
'child onBeforeUpdate',
'child onUpdated',
// 'mid onUpdated',
// 'root onUpdated',
])

calls.length = 0

// root update
rootCounter.value++
await nextTick()
// FIXME: not called
// expect(calls).toEqual([
// 'root onBeforeUpdate',
// 'mid onBeforeUpdate',
// 'child onBeforeUpdate',
// 'child onUpdated',
// 'mid onUpdated',
// 'root onUpdated',
// ])
// Root update events should not be passed to children.
expect(calls).toEqual(['root onBeforeUpdate', 'root onUpdated'])

calls.length = 0

// unmount
toggle.value = false
// FIXME: not called
// expect(calls).toEqual([
// 'root onBeforeUnmount',
// 'mid onBeforeUnmount',
// 'child onBeforeUnmount',
// 'child onUnmounted',
// 'mid onUnmounted',
// 'root onUnmounted',
// ])
await nextTick()
expect(calls).toEqual([
'root onBeforeUpdate',
'mid onBeforeUnmount',
'child onBeforeUnmount',
'child onUnmounted',
'mid onUnmounted',
'root onUpdated',
])

calls.length = 0

// mount
toggle.value = true
await nextTick()
expect(calls).toEqual([
'root onBeforeUpdate',
'mid onBeforeMount',
'child onBeforeMount',
'child onMounted',
'mid onMounted',
'root onUpdated',
])
})

it('onRenderTracked', async () => {
@@ -458,7 +484,7 @@ describe('api: lifecycle hooks', () => {
expect(fn).toHaveBeenCalledTimes(2)
toggle.value = false
await nextTick()
// expect(fn).toHaveBeenCalledTimes(4) // FIXME: not called unmounted hook
expect(fn).toHaveBeenCalledTimes(4)
})

// #136
138 changes: 137 additions & 1 deletion packages/runtime-vapor/__tests__/component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
import { ref, setText, template, watchEffect } from '../src'
import {
type Directive,
createComponent,
createIf,
nextTick,
ref,
renderEffect,
setText,
template,
watchEffect,
withDirectives,
} from '../src'
import { describe, expect } from 'vitest'
import { makeRender } from './_utils'

@@ -19,4 +30,129 @@ describe('component', () => {
app.unmount()
expect(host.innerHTML).toBe('')
})

it('directive lifecycle hooks call order', async () => {
const rootCounter = ref(0)
const propsCounter = ref(0)
const toggle = ref(true)
const calls: string[] = []

const vDirective = (name: string): Directive => ({
created: () => calls.push(`${name} created`),
beforeMount: () => calls.push(`${name} beforeMount`),
mounted: () => calls.push(`${name} mounted`),
beforeUpdate: () => calls.push(`${name} beforeUpdate`),
updated: () => calls.push(`${name} updated`),
beforeUnmount: () => calls.push(`${name} beforeUnmount`),
unmounted: () => calls.push(`${name} unmounted`),
})

const { render } = define({
setup() {
return (() => {
const n0 = withDirectives(template('<p></p>')(), [
[vDirective('root')],
])
renderEffect(() => setText(n0, rootCounter.value))
const n1 = createIf(
() => toggle.value,
() => createComponent(Mid, { count: () => propsCounter.value }),
)
return [n0, n1]
})()
},
})

const Mid = {
props: ['count'],
setup(props: any) {
return (() => {
withDirectives(template('<p></p>')(), [[vDirective('mid')]])
const n0 = createComponent(Child, { count: () => props.count })
return n0
})()
},
}

const Child = {
props: ['count'],
setup(props: any) {
return (() => {
const t0 = template('<div></div>')
const n0 = t0()
withDirectives(n0, [[vDirective('child')]])
renderEffect(() => setText(n0, props.count))
return n0
})()
},
}

// mount
render()
expect(calls).toEqual([
'root created',
'mid created',
'child created',
'root beforeMount',
'mid beforeMount',
'child beforeMount',
'root mounted',
'mid mounted',
'child mounted',
])

calls.length = 0

// props update
propsCounter.value++
await nextTick()
// There are no calls in the root and mid,
// but maybe such performance would be better.
expect(calls).toEqual([
// 'root beforeUpdate',
// 'mid beforeUpdate',
'child beforeUpdate',
'child updated',
// 'mid updated',
// 'root updated',
])

calls.length = 0

// root update
rootCounter.value++
await nextTick()
// Root update events should not be passed to children.
expect(calls).toEqual(['root beforeUpdate', 'root updated'])

calls.length = 0

// unmount
toggle.value = false
await nextTick()
expect(calls).toEqual([
'root beforeUpdate',
'mid beforeUnmount',
'child beforeUnmount',
'mid unmounted',
'child unmounted',
'root updated',
])

calls.length = 0

// mount
toggle.value = true
await nextTick()
expect(calls).toEqual([
'root beforeUpdate',
'mid created',
'child created',
'mid beforeMount',
'child beforeMount',
'mid mounted',
'child mounted',
'root updated',
])
})
})
Loading