From 034b39dee529a29cec9ac4edd3d4ec57ad1b4328 Mon Sep 17 00:00:00 2001 From: Rizumu Ayaka Date: Sat, 16 Dec 2023 00:02:29 +0800 Subject: [PATCH 1/4] feat(runtime): beforeUpdate hook --- packages/runtime-vapor/src/directive.ts | 10 +++++++- packages/runtime-vapor/src/scheduler.ts | 32 +++++++++++++++++++------ 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/packages/runtime-vapor/src/directive.ts b/packages/runtime-vapor/src/directive.ts index 3906eb723..f2163a471 100644 --- a/packages/runtime-vapor/src/directive.ts +++ b/packages/runtime-vapor/src/directive.ts @@ -27,7 +27,7 @@ export type DirectiveHookName = | 'created' | 'beforeMount' | 'mounted' - // | 'beforeUpdate' + | 'beforeUpdate' | 'updated' | 'beforeUnmount' | 'unmounted' @@ -95,6 +95,14 @@ export function withDirectives( callDirectiveHook(node, binding, 'created') + effect( + () => { + if (!instance.isMountedRef.value) return + callDirectiveHook(node, binding, 'beforeUpdate') + }, + { flush: 'pre' }, + ) + effect(() => { if (!instance.isMountedRef.value) return callDirectiveHook(node, binding, 'updated') diff --git a/packages/runtime-vapor/src/scheduler.ts b/packages/runtime-vapor/src/scheduler.ts index 876e2c45e..119213d95 100644 --- a/packages/runtime-vapor/src/scheduler.ts +++ b/packages/runtime-vapor/src/scheduler.ts @@ -2,9 +2,11 @@ import { ReactiveEffect } from '@vue/reactivity' const p = Promise.resolve() -let queued: any[] | undefined +let preQueued: any[] | undefined +let renderQueued: any[] | undefined +let postQueued: any[] | undefined -function queue(fn: any) { +function queue(fn: any, queued: any[] | undefined) { if (!queued) { queued = [fn] p.then(flush) @@ -14,17 +16,33 @@ function queue(fn: any) { } function flush() { - for (let i = 0; i < queued!.length; i++) { - queued![i]() + flushAQueued(preQueued) + flushAQueued(renderQueued) + flushAQueued(postQueued) +} + +function flushAQueued(queued: any[] | undefined) { + if (queued) { + for (let i = 0; i < queued.length; i++) { + queued[i]() + } + queued = undefined } - queued = undefined } export const nextTick = (fn?: any) => (fn ? p.then(fn) : p) -export function effect(fn: any) { +export function effect(fn: any, options: any) { let run: () => void - const e = new ReactiveEffect(fn, () => queue(run)) + + const queued = + options.flush === 'pre' + ? preQueued + : options.flush === 'post' + ? postQueued + : renderQueued + + const e = new ReactiveEffect(fn, () => queue(run, queued)) run = e.run.bind(e) run() } From f89c97346fd44a016883ee298329a9dd4f61f668 Mon Sep 17 00:00:00 2001 From: Rizumu Ayaka Date: Sat, 16 Dec 2023 00:47:35 +0800 Subject: [PATCH 2/4] fix: it doesn't work. --- packages/runtime-vapor/src/directive.ts | 19 ++++++++---- packages/runtime-vapor/src/scheduler.ts | 40 ++++++++++++++----------- 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/packages/runtime-vapor/src/directive.ts b/packages/runtime-vapor/src/directive.ts index f2163a471..e5d7fb68c 100644 --- a/packages/runtime-vapor/src/directive.ts +++ b/packages/runtime-vapor/src/directive.ts @@ -103,10 +103,13 @@ export function withDirectives( { flush: 'pre' }, ) - effect(() => { - if (!instance.isMountedRef.value) return - callDirectiveHook(node, binding, 'updated') - }) + effect( + () => { + if (!instance.isMountedRef.value) return + callDirectiveHook(node, binding, 'updated') + }, + { flush: 'post' }, + ) } return node @@ -137,9 +140,13 @@ function callDirectiveHook( if (!hook) return const newValue = binding.source ? binding.source() : undefined - if (name === 'updated' && binding.value === newValue) return + if ( + ['updated', 'beforeUpdate'].includes(name) && + newValue === binding.oldValue + ) + return - binding.oldValue = binding.value binding.value = newValue hook(node, binding) + if (name === 'updated') binding.oldValue = newValue } diff --git a/packages/runtime-vapor/src/scheduler.ts b/packages/runtime-vapor/src/scheduler.ts index 119213d95..447db74ed 100644 --- a/packages/runtime-vapor/src/scheduler.ts +++ b/packages/runtime-vapor/src/scheduler.ts @@ -2,16 +2,17 @@ import { ReactiveEffect } from '@vue/reactivity' const p = Promise.resolve() -let preQueued: any[] | undefined -let renderQueued: any[] | undefined -let postQueued: any[] | undefined - -function queue(fn: any, queued: any[] | undefined) { - if (!queued) { - queued = [fn] +type Queued = { value?: any[] } +let preQueued: Queued = {} +let renderQueued: Queued = {} +let postQueued: Queued = {} + +function queue(fn: any, queued: Queued) { + if (!queued.value) { + queued.value = [fn] p.then(flush) } else { - queued.push(fn) + queued.value.push(fn) } } @@ -21,26 +22,31 @@ function flush() { flushAQueued(postQueued) } -function flushAQueued(queued: any[] | undefined) { - if (queued) { - for (let i = 0; i < queued.length; i++) { - queued[i]() +function flushAQueued(queued: Queued) { + if (queued.value) { + for (let i = 0; i < queued.value.length; i++) { + queued.value[i]() } - queued = undefined } + queued.value = undefined } export const nextTick = (fn?: any) => (fn ? p.then(fn) : p) -export function effect(fn: any, options: any) { +export type EffectOptions = { + flush?: 'pre' | 'post' | 'render' +} + +export function effect(fn: any, options?: EffectOptions) { let run: () => void + const flushMode = options?.flush const queued = - options.flush === 'pre' + flushMode === 'pre' ? preQueued - : options.flush === 'post' + : flushMode === 'post' ? postQueued - : renderQueued + : renderQueued // default const e = new ReactiveEffect(fn, () => queue(run, queued)) run = e.run.bind(e) From 55a4dadd7e031936063493665a03c38c851e0922 Mon Sep 17 00:00:00 2001 From: Rizumu Ayaka Date: Sat, 16 Dec 2023 01:29:36 +0800 Subject: [PATCH 3/4] fix: v-show test --- packages/runtime-vapor/src/directive.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime-vapor/src/directive.ts b/packages/runtime-vapor/src/directive.ts index e5d7fb68c..926750dc6 100644 --- a/packages/runtime-vapor/src/directive.ts +++ b/packages/runtime-vapor/src/directive.ts @@ -148,5 +148,5 @@ function callDirectiveHook( binding.value = newValue hook(node, binding) - if (name === 'updated') binding.oldValue = newValue + if (name != 'beforeUpdate') binding.oldValue = binding.value } From 952a93e71c93a9a7b4cecd793478eb2df1fbf2dd Mon Sep 17 00:00:00 2001 From: Rizumu Ayaka Date: Sat, 16 Dec 2023 01:31:03 +0800 Subject: [PATCH 4/4] chore: organize code --- packages/runtime-vapor/src/directive.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime-vapor/src/directive.ts b/packages/runtime-vapor/src/directive.ts index 926750dc6..3f63022ae 100644 --- a/packages/runtime-vapor/src/directive.ts +++ b/packages/runtime-vapor/src/directive.ts @@ -148,5 +148,5 @@ function callDirectiveHook( binding.value = newValue hook(node, binding) - if (name != 'beforeUpdate') binding.oldValue = binding.value + if (name !== 'beforeUpdate') binding.oldValue = binding.value }