Ownership and memory
Everything a component creates (effects, memos, cleanups) belongs to the owner it was created under and is disposed with it.
Everything a component creates (effects, memos, cleanups) belongs to the owner it was created under and is disposed with it. A leak is something created outside an owner or that outlives it:
- Effects at module scope have no owner and are never disposed. Core warns
NO_OWNER_EFFECTin development. Wrap them increateRootand keep thedisposefunction. - Timers, listeners, observers, sockets: register their teardown with
onCleanup(or return it fromuseEffect) in the same scope that created them. - Callbacks after
awaitlose the owner. Capture it withgetOwner()and userunWithOwner. - Detached roots (
createRoot(fn, { detached: true })) are disposed only by their owndispose.
src/lifecycle.tsxtsx
import { onCleanup, useEffect } from "@shadow-js/core";
import { Show } from "@shadow-js/web";
export const live = { listeners: 0, created: 0, disposed: 0 };
export function Tracker() {
live.created += 1;
const onResize = (): void => undefined;
window.addEventListener("resize", onResize);
live.listeners += 1;
onCleanup(() => {
window.removeEventListener("resize", onResize);
live.listeners -= 1;
live.disposed += 1;
});
useEffect(() => {
// Tracked work would go here; its own cleanup runs before each rerun.
});
return <i>tracking</i>;
}
export function Panel(props: { open: () => boolean }) {
return (
<Show when={props.open()}>
<Tracker />
</Show>
);
}