test(vapor): lifecycle (partial)

This commit is contained in:
Evan You 2024-12-10 15:30:21 +08:00
parent 89707e8b5f
commit c2e7312da4
No known key found for this signature in database
GPG Key ID: 00E9AB7A6704CE0A
2 changed files with 121 additions and 130 deletions

View File

@ -4,10 +4,7 @@ import {
type Ref,
TrackOpTypes,
TriggerOpTypes,
createComponent,
createIf,
createTextNode,
getCurrentInstance,
currentInstance,
inject,
nextTick,
onBeforeMount,
@ -21,6 +18,11 @@ import {
provide,
reactive,
ref,
} from '@vue/runtime-dom'
import {
createComponent,
// createIf,
createTextNode,
renderEffect,
setText,
template,
@ -30,7 +32,7 @@ import { ITERATE_KEY } from '@vue/reactivity'
const define = makeRender<any>()
describe.todo('api: lifecycle hooks', () => {
describe('api: lifecycle hooks', () => {
it('onBeforeMount', () => {
const fn = vi.fn(() => {
expect(host.innerHTML).toBe(``)
@ -38,7 +40,7 @@ describe.todo('api: lifecycle hooks', () => {
const { render, host } = define({
setup() {
onBeforeMount(fn)
return () => template('<div></div>')()
return []
},
})
render()
@ -52,7 +54,7 @@ describe.todo('api: lifecycle hooks', () => {
const { render, host } = define({
setup() {
onMounted(fn)
return () => template('<div></div>')()
return []
},
})
render()
@ -67,13 +69,11 @@ describe.todo('api: lifecycle hooks', () => {
const { render, host } = define({
setup() {
onBeforeUpdate(fn)
return (() => {
const n0 = createTextNode()
renderEffect(() => {
setText(n0, count.value)
})
return n0
})()
const n0 = createTextNode()
renderEffect(() => {
setText(n0, count.value)
})
return n0
},
})
render()
@ -94,14 +94,12 @@ describe.todo('api: lifecycle hooks', () => {
const { render, host } = define({
setup() {
onBeforeUpdate(fn)
return (() => {
const n0 = createTextNode()
renderEffect(() => {
renderSpy()
setText(n0, count.value)
})
return n0
})()
const n0 = createTextNode()
renderEffect(() => {
renderSpy()
setText(n0, count.value)
})
return n0
},
})
render()
@ -117,13 +115,12 @@ describe.todo('api: lifecycle hooks', () => {
const { render, host } = define({
setup() {
onUpdated(fn)
return (() => {
const n0 = createTextNode()
renderEffect(() => {
setText(n0, count.value)
})
return n0
})()
const n0 = createTextNode()
renderEffect(() => {
setText(n0, count.value)
})
return n0
},
})
render()
@ -133,31 +130,29 @@ describe.todo('api: lifecycle hooks', () => {
expect(fn).toHaveBeenCalledTimes(1)
})
it('onBeforeUnmount', async () => {
it.todo('onBeforeUnmount', async () => {
const toggle = ref(true)
const fn = vi.fn(() => {
expect(host.innerHTML).toBe('<div></div>')
})
const { render, host } = define({
setup() {
return (() => {
const n0 = createIf(
() => toggle.value,
() => createComponent(Child),
)
return n0
})()
// @ts-expect-error
const n0 = createIf(
() => toggle.value,
() => createComponent(Child),
)
return n0
},
})
const Child = {
setup() {
onBeforeUnmount(fn)
return (() => {
const t0 = template('<div></div>')
const n0 = t0()
return n0
})()
const t0 = template('<div></div>')
const n0 = t0()
return n0
},
}
@ -169,31 +164,29 @@ describe.todo('api: lifecycle hooks', () => {
expect(host.innerHTML).toBe('<!--if-->')
})
it('onUnmounted', async () => {
it.todo('onUnmounted', async () => {
const toggle = ref(true)
const fn = vi.fn(() => {
expect(host.innerHTML).toBe('<div></div>')
})
const { render, host } = define({
setup() {
return (() => {
const n0 = createIf(
() => toggle.value,
() => createComponent(Child),
)
return n0
})()
// @ts-expect-error
const n0 = createIf(
() => toggle.value,
() => createComponent(Child),
)
return n0
},
})
const Child = {
setup() {
onUnmounted(fn)
return (() => {
const t0 = template('<div></div>')
const n0 = t0()
return n0
})()
const t0 = template('<div></div>')
const n0 = t0()
return n0
},
}
@ -205,20 +198,19 @@ describe.todo('api: lifecycle hooks', () => {
expect(host.innerHTML).toBe('<!--if-->')
})
it('onBeforeUnmount in onMounted', async () => {
it.todo('onBeforeUnmount in onMounted', async () => {
const toggle = ref(true)
const fn = vi.fn(() => {
expect(host.innerHTML).toBe('<div></div>')
})
const { render, host } = define({
setup() {
return (() => {
const n0 = createIf(
() => toggle.value,
() => createComponent(Child),
)
return n0
})()
// @ts-expect-error
const n0 = createIf(
() => toggle.value,
() => createComponent(Child),
)
return n0
},
})
@ -227,11 +219,10 @@ describe.todo('api: lifecycle hooks', () => {
onMounted(() => {
onBeforeUnmount(fn)
})
return (() => {
const t0 = template('<div></div>')
const n0 = t0()
return n0
})()
const t0 = template('<div></div>')
const n0 = t0()
return n0
},
}
@ -243,7 +234,7 @@ describe.todo('api: lifecycle hooks', () => {
expect(host.innerHTML).toBe('<!--if-->')
})
it('lifecycle call order', async () => {
it.todo('lifecycle call order', async () => {
const count = ref(0)
const toggle = ref(true)
const calls: string[] = []
@ -256,13 +247,13 @@ describe.todo('api: lifecycle hooks', () => {
onUpdated(() => calls.push('onUpdated'))
onBeforeUnmount(() => calls.push('onBeforeUnmount'))
onUnmounted(() => calls.push('onUnmounted'))
return (() => {
const n0 = createIf(
() => toggle.value,
() => createComponent(Mid, { count: () => count.value }),
)
return n0
})()
// @ts-expect-error
const n0 = createIf(
() => toggle.value,
() => createComponent(Mid, { count: () => count.value }),
)
return n0
},
})
@ -275,10 +266,9 @@ describe.todo('api: lifecycle hooks', () => {
onUpdated(() => calls.push('mid onUpdated'))
onBeforeUnmount(() => calls.push('mid onBeforeUnmount'))
onUnmounted(() => calls.push('mid onUnmounted'))
return (() => {
const n0 = createComponent(Child, { count: () => props.count })
return n0
})()
const n0 = createComponent(Child, { count: () => props.count })
return n0
},
}
@ -291,12 +281,11 @@ describe.todo('api: lifecycle hooks', () => {
onUpdated(() => calls.push('child onUpdated'))
onBeforeUnmount(() => calls.push('child onBeforeUnmount'))
onUnmounted(() => calls.push('child onUnmounted'))
return (() => {
const t0 = template('<div></div>')
const n0 = t0()
renderEffect(() => setText(n0, props.count))
return n0
})()
const t0 = template('<div></div>')
const n0 = t0()
renderEffect(() => setText(n0, props.count))
return n0
},
}
@ -351,13 +340,12 @@ describe.todo('api: lifecycle hooks', () => {
const { render } = define({
setup() {
onRenderTracked(onTrack)
return (() => {
const n0 = createTextNode()
renderEffect(() => {
setText(n0, [obj.foo, 'bar' in obj, Object.keys(obj).join('')])
})
return n0
})()
const n0 = createTextNode()
renderEffect(() => {
setText(n0, [obj.foo, 'bar' in obj, Object.keys(obj).join('')])
})
return n0
},
})
@ -395,13 +383,12 @@ describe.todo('api: lifecycle hooks', () => {
const { render } = define({
setup() {
onRenderTriggered(onTrigger)
return (() => {
const n0 = createTextNode()
renderEffect(() => {
setText(n0, [obj.foo, 'bar' in obj, Object.keys(obj).join('')])
})
return n0
})()
const n0 = createTextNode()
renderEffect(() => {
setText(n0, [obj.foo, 'bar' in obj, Object.keys(obj).join('')])
})
return n0
},
})
@ -435,11 +422,12 @@ describe.todo('api: lifecycle hooks', () => {
})
})
it('runs shared hook fn for each instance', async () => {
it.todo('runs shared hook fn for each instance', async () => {
const fn = vi.fn()
const toggle = ref(true)
const { render } = define({
setup() {
// @ts-expect-error
return createIf(
() => toggle.value,
() => [createComponent(Child), createComponent(Child)],
@ -471,12 +459,11 @@ describe.todo('api: lifecycle hooks', () => {
const { render, host } = define({
setup() {
onUpdated(() => handleUpdated())
return (() => {
const n0 = createTextNode()
renderEffect(() => setText(n0, count.value))
const n1 = createComponent(Child, { count: () => count.value })
return [n0, n1]
})()
const n0 = createTextNode()
renderEffect(() => setText(n0, count.value))
const n1 = createComponent(Child, { count: () => count.value })
return [n0, n1]
},
})
@ -484,12 +471,11 @@ describe.todo('api: lifecycle hooks', () => {
props: { count: Number },
setup() {
onUpdated(() => handleUpdatedChild())
return (() => {
const props = getCurrentInstance()!.props
const n2 = createTextNode()
renderEffect(() => setText(n2, props.count))
return n2
})()
const props = currentInstance!.props
const n2 = createTextNode()
renderEffect(() => setText(n2, props.count))
return n2
},
}
@ -518,12 +504,11 @@ describe.todo('api: lifecycle hooks', () => {
const count = ref(0)
provide(key, count)
onUpdated(() => handleUpdated())
return (() => {
const n0 = createTextNode()
renderEffect(() => setText(n0, count.value))
const n1 = createComponent(Child, { count: () => count.value })
return [n0, n1]
})()
const n0 = createTextNode()
renderEffect(() => setText(n0, count.value))
const n1 = createComponent(Child, { count: () => count.value })
return [n0, n1]
},
})
@ -534,11 +519,10 @@ describe.todo('api: lifecycle hooks', () => {
onUpdated(() => handleUpdatedChild())
const count = inject(key)!
update = () => count.value++
return (() => {
const n2 = createTextNode()
renderEffect(() => setText(n2, count.value))
return n2
})()
const n2 = createTextNode()
renderEffect(() => setText(n2, count.value))
return n2
},
}

View File

@ -18,6 +18,8 @@ export function renderEffect(fn: () => void, noLifecycle = false): void {
warn('renderEffect called without active vapor instance.')
}
// renderEffect is always called after user has registered all hooks
const hasUpdateHooks = instance && (instance.bu || instance.u)
const renderEffectFn = noLifecycle
? fn
: () => {
@ -27,12 +29,7 @@ export function renderEffect(fn: () => void, noLifecycle = false): void {
const prev = currentInstance
simpleSetCurrentInstance(instance)
if (scope) scope.on()
if (
instance &&
instance.isMounted &&
!instance.isUpdating &&
(instance.bu || instance.u)
) {
if (hasUpdateHooks && instance.isMounted && !instance.isUpdating) {
instance.isUpdating = true
instance.bu && invokeArrayFns(instance.bu)
fn()
@ -52,10 +49,20 @@ export function renderEffect(fn: () => void, noLifecycle = false): void {
const effect = new ReactiveEffect(renderEffectFn)
const job: SchedulerJob = effect.runIfDirty.bind(effect)
if (instance) {
if (__DEV__) {
effect.onTrack = instance.rtc
? e => invokeArrayFns(instance.rtc!, e)
: void 0
effect.onTrigger = instance.rtg
? e => invokeArrayFns(instance.rtg!, e)
: void 0
}
job.i = instance
job.id = instance.uid
}
effect.scheduler = () => queueJob(job)
effect.run()