Просмотр исходного кода

wip(vapor): updated/beforeUpdate

Evan You 1 год назад
Родитель
Сommit
30e24ce986

+ 6 - 1
packages/runtime-vapor/src/component.ts

@@ -185,6 +185,7 @@ export class VaporComponentInstance implements GenericComponentInstance {
   isMounted: boolean
   isUnmounted: boolean
   isDeactivated: boolean
+  isUpdating: boolean
 
   bc?: LifecycleHook // LifecycleHooks.BEFORE_CREATE
   c?: LifecycleHook // LifecycleHooks.CREATED
@@ -223,7 +224,11 @@ export class VaporComponentInstance implements GenericComponentInstance {
       : Object.create(this.appContext.provides)
     this.refs = EMPTY_OBJ
     this.emitted = this.ec = this.exposed = this.propsDefaults = null
-    this.isMounted = this.isUnmounted = this.isDeactivated = false
+    this.isMounted =
+      this.isUnmounted =
+      this.isUpdating =
+      this.isDeactivated =
+        false
 
     // init props
     const target = rawProps || EMPTY_OBJ

+ 1 - 1
packages/runtime-vapor/src/componentProps.ts

@@ -255,5 +255,5 @@ export function setupPropsValidation(instance: VaporComponentInstance): void {
       normalizePropsOptions(instance.type)[0]!,
     )
     popWarningContext()
-  })
+  }, true /* noLifecycle */)
 }

+ 8 - 3
packages/runtime-vapor/src/dom/element.ts

@@ -12,9 +12,14 @@ export function insert(
   if (block instanceof Node) {
     parent.insertBefore(block, anchor)
   } else if (isVaporComponent(block)) {
-    if (block.bm) invokeArrayFns(block.bm)
-    insert(block.block, parent, anchor)
-    if (block.m) invokeArrayFns(block.m)
+    if (!block.isMounted) {
+      if (block.bm) invokeArrayFns(block.bm)
+      insert(block.block, parent, anchor)
+      if (block.m) invokeArrayFns(block.m)
+      block.isMounted = true
+    } else {
+      insert(block.block, parent, anchor)
+    }
   } else if (isArray(block)) {
     for (let i = 0; i < block.length; i++) {
       insert(block[i], parent, anchor)

+ 39 - 7
packages/runtime-vapor/src/renderEffect.ts

@@ -1,14 +1,46 @@
 import { ReactiveEffect } from '@vue/reactivity'
-import { type SchedulerJob, currentInstance, queueJob } from '@vue/runtime-dom'
+import {
+  type SchedulerJob,
+  currentInstance,
+  queueJob,
+  queuePostFlushCb,
+  setCurrentInstance,
+  warn,
+} from '@vue/runtime-dom'
+import { type VaporComponentInstance, isVaporComponent } from './component'
+import { invokeArrayFns } from '@vue/shared'
 
-export function renderEffect(fn: () => void): void {
-  const updateFn = () => {
-    fn()
+export function renderEffect(fn: () => void, noLifecycle = false): void {
+  const instance = currentInstance as VaporComponentInstance
+  if (__DEV__ && !isVaporComponent(instance)) {
+    warn('renderEffect called without active vapor instance.')
   }
-  const effect = new ReactiveEffect(updateFn)
+
+  const effect = new ReactiveEffect(
+    noLifecycle
+      ? fn
+      : () => {
+          const reset = setCurrentInstance(instance)
+          const { isMounted, isUpdating, bu, u } = instance
+          // before update
+          if (isMounted && !isUpdating && (bu || u)) {
+            instance.isUpdating = true
+            bu && invokeArrayFns(bu)
+            fn()
+            queuePostFlushCb(() => {
+              instance.isUpdating = false
+              u && invokeArrayFns(u)
+            })
+          } else {
+            fn()
+          }
+          reset()
+        },
+  )
+
   const job: SchedulerJob = effect.runIfDirty.bind(effect)
-  job.i = currentInstance as any
-  job.id = currentInstance!.uid
+  job.i = instance
+  job.id = instance.uid
   effect.scheduler = () => queueJob(job)
   effect.run()