浏览代码

refactor(vapor): move KeepAlive scope caching to fragment hooks

daiwei 2 周之前
父节点
当前提交
b68e199dcb
共有 2 个文件被更改,包括 31 次插入24 次删除
  1. 21 5
      packages/runtime-vapor/src/components/KeepAlive.ts
  2. 10 19
      packages/runtime-vapor/src/fragment.ts

+ 21 - 5
packages/runtime-vapor/src/components/KeepAlive.ts

@@ -40,6 +40,7 @@ import {
   type VaporKeepAliveContext,
   currentCacheKey,
   setCurrentKeepAliveCtx,
+  withCurrentCacheKey,
   withKeepAliveEnabled,
 } from '../keepAlive'
 
@@ -384,12 +385,12 @@ const VaporKeepAliveImpl = defineVaporComponent({
     const prevCtx = setCurrentKeepAliveCtx(keepAliveCtx)
     let children = slots.default()
     setCurrentKeepAliveCtx(prevCtx)
-    registerDynamicFragmentUpdated(children, cacheBlock)
+    registerDynamicFragmentHooks(children, keepAliveCtx)
 
     if (isArray(children)) {
       children = children.filter(child => !(child instanceof Comment))
       if (children.length === 1) {
-        registerDynamicFragmentUpdated(children[0], cacheBlock)
+        registerDynamicFragmentHooks(children[0], keepAliveCtx)
       }
       if (children.length > 1) {
         if (__DEV__) {
@@ -406,16 +407,31 @@ const VaporKeepAliveImpl = defineVaporComponent({
 export const VaporKeepAlive: DefineVaporComponent<{}, string, KeepAliveProps> =
   /*@__PURE__*/ withKeepAliveEnabled(VaporKeepAliveImpl)
 
-function registerDynamicFragmentUpdated(
+function registerDynamicFragmentHooks(
   block: Block,
-  cacheBlock: (block?: Block) => void,
+  keepAliveCtx: VaporKeepAliveContext,
 ): void {
   if (!isDynamicFragment(block)) return
+
+  ;(block.onBeforeRemove ||= []).push(scope => {
+    // If processShapeFlag returns a cache key, cache the scope and retain it.
+    const cacheKey = block.keyed
+      ? withCurrentCacheKey(block.current, () =>
+          keepAliveCtx.processShapeFlag(block.nodes),
+        )
+      : keepAliveCtx.processShapeFlag(block.nodes)
+    if (cacheKey !== false) {
+      keepAliveCtx.cacheScope(cacheKey, block.current, scope)
+      return true
+    }
+    return false
+  })
+
   ;(block.onUpdated ||= []).unshift(() => {
     if (block.$transition && block.$transition.mode === 'out-in') {
       // For out-in transition, call cacheBlock after renderBranch completes
       // because KeepAlive's onUpdated fires before the deferred rendering finishes.
-      cacheBlock(block)
+      keepAliveCtx.cacheBlock(block)
     }
   })
 }

+ 10 - 19
packages/runtime-vapor/src/fragment.ts

@@ -88,8 +88,10 @@ export class VaporFragment<
   ) => void
 
   // hooks
-  onBeforeUpdate?: (() => void)[]
   onBeforeInsert?: ((nodes: Block) => void)[]
+  // Return true to keep the branch scope alive after removing its DOM.
+  onBeforeRemove?: ((scope: EffectScope) => boolean)[]
+  onBeforeUpdate?: (() => void)[]
   onUpdated?: ((nodes?: Block) => void)[]
 
   // render context
@@ -300,29 +302,18 @@ export class DynamicFragment extends VaporFragment {
     const parent = isHydrating ? null : this.anchor.parentNode
     // teardown previous branch
     if (this.current !== undefined) {
-      if (this.scope && isKeepAliveEnabled) {
+      const scope = this.scope
+      if (scope) {
         let retainScope = false
-        const keepAliveCtx = this.keepAliveCtx
-
-        // if keepAliveCtx exists and processShapeFlag returns a cache key,
-        // cache the scope and retain it.
-        if (keepAliveCtx) {
-          const cacheKey = this.keyed
-            ? withCurrentCacheKey(this.current, () =>
-                keepAliveCtx.processShapeFlag(this.nodes),
-              )
-            : keepAliveCtx.processShapeFlag(this.nodes)
-          if (cacheKey !== false) {
-            keepAliveCtx.cacheScope(cacheKey, this.current, this.scope)
-            retainScope = true
+        const onBeforeRemove = this.onBeforeRemove
+        if (onBeforeRemove) {
+          for (let i = 0; i < onBeforeRemove.length; i++) {
+            retainScope = onBeforeRemove[i](scope) || retainScope
           }
         }
-
         if (!retainScope) {
-          this.scope.stop()
+          scope.stop()
         }
-      } else if (this.scope) {
-        this.scope.stop()
       }
       const mode = transition && transition.mode