Skip to content
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

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
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
Expand Up @@ -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() {
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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]
})()
},
})
Expand Down Expand Up @@ -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 () => {
Expand Down Expand Up @@ -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
Expand Down
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'

Expand All @@ -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
Loading