Implement disposeFiber for fiber tree disposal
Add disposeFiber() function that performs bottom-up teardown of fiber subtrees: recursively disposes children before parents, calls host.finalizeInstance for per-instance cleanup, invokes signal disposers, and clears fiber state. Idempotent via disposed flag. Does NOT call host.removeChild (that's the commit phase's job). - Add disposeFiber + HostLike to src/host/fiber.ts - Add finalizeInstance to HostConfig interface - Add disposed boolean to Fiber interface - Export disposeFiber and HostLike from barrel - Add 7 tests for disposeFiber (3-level tree, idempotency, signal cleanup, etc.)
This commit is contained in:
@@ -30,6 +30,7 @@ export interface HostConfig<TTag extends string, Instance, RootCtx> {
|
||||
ctx: RootCtx,
|
||||
): void;
|
||||
emit?(type: string, id: string, payload: unknown): void;
|
||||
finalizeInstance?(instance: Instance, ctx: RootCtx): void;
|
||||
}
|
||||
|
||||
export interface Root<TTag extends string, Instance, RootCtx> {
|
||||
@@ -70,6 +71,7 @@ export function createRoot<TTag extends string, Instance, RootCtx>(
|
||||
effect: null,
|
||||
signalDisposers: [],
|
||||
prevProps: null,
|
||||
disposed: false,
|
||||
};
|
||||
if (parentFiber) parentFiber.children.push(fiber);
|
||||
return fiber;
|
||||
@@ -106,6 +108,7 @@ export function createRoot<TTag extends string, Instance, RootCtx>(
|
||||
effect: null,
|
||||
signalDisposers: [],
|
||||
prevProps: null,
|
||||
disposed: false,
|
||||
};
|
||||
|
||||
for (const child of el.children) {
|
||||
@@ -132,6 +135,7 @@ export function createRoot<TTag extends string, Instance, RootCtx>(
|
||||
effect: null,
|
||||
signalDisposers: [],
|
||||
prevProps: null,
|
||||
disposed: false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -158,6 +162,7 @@ export function createRoot<TTag extends string, Instance, RootCtx>(
|
||||
effect: null,
|
||||
signalDisposers: [],
|
||||
prevProps: null,
|
||||
disposed: false,
|
||||
};
|
||||
|
||||
for (const child of el.children) {
|
||||
@@ -281,6 +286,7 @@ export function createRoot<TTag extends string, Instance, RootCtx>(
|
||||
effect: null,
|
||||
signalDisposers: [],
|
||||
prevProps: null,
|
||||
disposed: false,
|
||||
};
|
||||
const payloadChildren = isURoot(node) ? (node as URoot).children : [node];
|
||||
for (const child of payloadChildren) {
|
||||
|
||||
@@ -8,10 +8,34 @@ export interface Fiber<I> {
|
||||
effect: Effect<I> | null;
|
||||
signalDisposers: (() => void)[];
|
||||
prevProps: Record<string, unknown> | null;
|
||||
disposed: boolean;
|
||||
}
|
||||
|
||||
export type Effect<I> =
|
||||
| { type: "update"; payload: unknown }
|
||||
| { type: "insert"; before: Fiber<I> | null }
|
||||
| { type: "move"; before: Fiber<I> | null }
|
||||
| { type: "remove" };
|
||||
| { type: "remove" };
|
||||
|
||||
export interface HostLike<I, Ctx> {
|
||||
finalizeInstance?(instance: I, ctx: Ctx): void;
|
||||
}
|
||||
|
||||
export function disposeFiber<I, Ctx>(fiber: Fiber<I>, host: HostLike<I, Ctx>, ctx: Ctx): void {
|
||||
if (fiber.disposed) return;
|
||||
|
||||
for (const child of fiber.children) {
|
||||
disposeFiber(child, host, ctx);
|
||||
}
|
||||
|
||||
host.finalizeInstance?.(fiber.instance, ctx);
|
||||
|
||||
for (const disposer of fiber.signalDisposers) {
|
||||
disposer();
|
||||
}
|
||||
fiber.signalDisposers = [];
|
||||
|
||||
fiber.parent = null;
|
||||
fiber.effect = null;
|
||||
fiber.disposed = true;
|
||||
}
|
||||
@@ -19,7 +19,8 @@ export { ValuePointer, selectNode, setNode } from "./core/pointer.js";
|
||||
export { createRoot as createHostRoot } from "./host/config.js";
|
||||
export type { HostConfig, Root } from "./host/config.js";
|
||||
|
||||
export type { Fiber, Effect } from "./host/fiber.js";
|
||||
export { disposeFiber } from "./host/fiber.js";
|
||||
export type { Fiber, Effect, HostLike } from "./host/fiber.js";
|
||||
|
||||
export { scheduleUpdate, flushUpdates, reconcileProps, commitEffects, commitMutations, wireSignalToFiber, resetUpdateQueue, reconcileChildren, longestIncreasingSubsequence } from "./host/reconcile.js";
|
||||
export type { MatchedChild, ChildClassification, CommitContext } from "./host/reconcile.js";
|
||||
|
||||
Reference in New Issue
Block a user