スコープとライフサイクル
現在のコンポーネントスコープに、セットアップ時のリソース、ブラウザでの有効化、effect、クリーンアップを登録します。
現在の所有者を取得する
同期的なコンポーネントのセットアップ中、または Show や For のファクトリ内で getScope を呼び、その関数をレンダリングしている所有者に作業を登録します。セットアップ中に直接呼んだヘルパーは同じ所有者を共有し、独立したスコープは作りません。
import type { ReadonlySignal } from "@takazudo/zfb/zudo-react";
import { getScope, signal } from "@takazudo/zfb/zudo-react";
function Clock() {
const scope = getScope();
const now = signal(Date.now());
scope.onActivate(() => {
const timer = window.setInterval(() => {
now.value = Date.now();
}, 1000);
return () => window.clearInterval(timer);
});
return <time>{now}</time>;
}getScope はセットアップ専用です。現在のレンダリング所有者がいない場所で呼ぶと ZR_NO_SCOPE が発生します。await を越えて所有者は維持されないため、非同期セットアップには対応しません。純粋な SDK コンストラクターは記述を作るだけなので、スコープなしでも呼べます。
セットアップと有効化を分ける
同期的なリソースのクリーンアップは onCleanup に登録します。ブラウザだけで行う起動処理は onActivate に登録し、そのコールバックから同期的なクリーンアップを返すこともできます。追跡されるブラウザの effect は effect に登録します。
function PageTitle({ title }: { title: ReadonlySignal<string> }) {
const scope = getScope();
scope.effect(() => {
document.title = title.value;
});
return <h1>{title}</h1>;
}有効化コールバックはブラウザでのみ、DOM のコミット後に実行されます。レンダラーはすべての ref をコールバックより前に設定します。子スコープは親より先に有効化され、兄弟は出力順、一つのスコープ内のコールバックは登録順に進みます。すべての有効化コールバックが終わった後、スケジューラーの最初の effect 段階で effect が始まります。サーバーではブラウザの有効化も effect も実行されません。
effect はコールバック中に読み取った値を追跡します。再実行前には前回のクリーンアップが追跡なしで実行されます。最後のクリーンアップはスコープの破棄時に実行されます。effect が例外を投げると報告され、古い依存関係は解除されますが、ほかの effect は続行します。
有効化に失敗すると、ランタイムはそのルートのリソースを破棄して失敗を報告します。すでに外部の状態を変えたユーザーコードは自分でクリーンアップを用意する必要があります。ランタイムは任意の副作用を取り消せません。
Promise を返すクリーンアップは無効です。クリーンアップコールバックは同期的で、スコープが有効な間に登録する必要があります。後で非同期処理を行うコールバックは提供される abort signal を使い、結果を反映する前に状態を確認してください。
破棄しても DOM は削除されない
スコープを破棄すると、所有者を無効にし、signal を abort し、キューにあるジョブを止め、子スコープを破棄します。ノードがまだ存在する間に登録の逆順でクリーンアップを実行し、最後に ref をクリアします。クリーンアップ中にエラーが起きても報告して続行します。破棄した作業は再び有効化できません。
マウント済みルートの dispose はランタイムのリソースを解放しますが、ラッパーとその DOM は残します。unmount は破棄に加え、そのハンドルが所有するノードを削除し、ラッパーは残します。zfb はラッパーの内容を自分で置き換える前に破棄を使います。ルートの削除や保留中のトリガーの取り消しで、以後の有効化を防げます。
クライアントのルートハンドルは identity と破棄状態を公開します。hydrate は既存のノードを引き継ぎ、mount は新しい子 DOM を作ります。どちらも想定される失敗を報告して null を返し、部分的に有効なハンドルは返しません。zfb はルートごとにエラーを分離するため、一つの島が壊れてもほかのルートの処理は続きます。
サーバーレンダリングは一時的なスコープグラフを所有し、エラーの場合も含め、レンダリング終了時に必ず破棄します。リクエスト固有の可変状態はモジュールレベルの変数ではなくレンダリング内に置いてください。