diff --git a/arkoala-arkts/arkui/src/LazyForEach.ts b/arkoala-arkts/arkui/src/LazyForEach.ts index 675a02dcb1969b88a66c489a011c22771d2de2df..89396ba1d1d0e4da2fb0046df1d8093b75c5dd8f 100644 --- a/arkoala-arkts/arkui/src/LazyForEach.ts +++ b/arkoala-arkts/arkui/src/LazyForEach.ts @@ -165,6 +165,7 @@ export function LazyForEach(dataSource: IDataSource, // console.log(`LazyForEach current=${current.value} version=${version.value} mark=${mark.value}`) let parent = contextNode() + console.log(`LazyForEach parent = ${parent.toString()}`) const offset = getOffset(parent, __id()) let listener = remember(() => new InternalListener(parent.peer.ptr)) diff --git a/incremental/runtime/src/states/State.ts b/incremental/runtime/src/states/State.ts index 5923d582b912aab4a8e4e19a688ff958167c6513..0e65b197ecab95b0e3f110c199932b27b8cd0a02 100644 --- a/incremental/runtime/src/states/State.ts +++ b/incremental/runtime/src/states/State.ts @@ -429,6 +429,16 @@ class ArrayStateImpl extends StateImpl> implements ArrayState< } } +class ScopeRecycler { + static pool = new Array() + static recycle(scope: ManagedScope) { + ScopeRecycler.pool.push(scope) + } + static reuse(): ManagedScope | undefined { + return ScopeRecycler.pool.pop() + } +} + class ParameterImpl implements MutableState { private manager: StateManagerImpl | undefined = undefined private dependencies: Dependencies | undefined = undefined @@ -783,7 +793,7 @@ class ScopeImpl implements ManagedScope, InternalScope, Computable parentScope: ManagedScope | undefined = undefined next: ManagedScope | undefined = undefined - private readonly _id: KoalaCallsiteKey + private _id: KoalaCallsiteKey private _once: boolean = false private _node: IncrementalNode | undefined = undefined private _nodeRef: IncrementalNode | undefined = undefined @@ -865,7 +875,23 @@ class ScopeImpl implements ManagedScope, InternalScope, Computable } } if (once != true && this.once) throw new Error("prohibited to create scope(" + KoalaCallsiteKeys.asString(id) + ") within the remember scope(" + KoalaCallsiteKeys.asString(this.id) + ")") - const scope = new ScopeImpl(id, paramCount, compute, cleanup) + + let reuse: ScopeImpl | undefined = + manager.node?.toString() === "@koalaui.arkts-arkui.generated.peers.ArkGridPeer.ArkGridPeer: 11" ? (ScopeRecycler.reuse() as ScopeImpl | undefined) : undefined; + if (reuse) { + reuse._id = id; + // find first node under reused scope + let scope : ManagedScope = reuse + while (!scope.node) { + if (!scope.next) { + throw new Error("node not found under scope") + } + scope = scope.next!! + } + scope.node!.incrementalUpdateDone(this.nodeRef) + } + + const scope = reuse ?? new ScopeImpl(id, paramCount, compute, cleanup); scope.manager = manager if (create) { // create node within a scope @@ -900,10 +926,13 @@ class ScopeImpl implements ManagedScope, InternalScope, Computable const manager = this.manager if (manager === undefined) throw new Error("unexpected") const scope = manager.current + + // cache scopes under Grid + const recycle = manager.node?.toString() === "@koalaui.arkts-arkui.generated.peers.ArkGridPeer.ArkGridPeer: 11" manager.current = undefined // allow to dispose children during recomputation while (child != last) { if (child === undefined) throw new Error("unexpected") - child.dispose() + recycle ? ScopeRecycler.recycle(child) : child.dispose() child = child.next } manager.current = scope