signals-preact-dart について
シグナルでアプリ状態を管理するDart開発者向けに、`preact_signals`パッケージによるリアクティブプログラミングを解説します。基本プリミティブ、依存関係の追跡、バッチ処理、循環を避けるルールを扱います。
主な機能
- 01可変シグナルと読み取り専用シグナル
- 02遅延評価・メモ化された計算値
- 03依存関係を動的に追跡するエフェクト
- 04複数の状態書き込みのバッチ処理
- 05依存関係の循環と再入ルールの説明
活用シーン
- 01リアクティブなアプリ状態のモデル化
- 02複数のシグナルから値を導出
- 03追跡対象の状態変更時に副作用を実行
- 04状態更新を1つのバッチにまとめる
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ rodydavis/ signals.dart --skill signals-preact-dartインストール後、Claude Code で/signals-preact-dartを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
CONTEXT.mdcore/batch.mdcomputed.mdCONTEXT.mdeffect.mdreadonly.mdsignal.md詳細
Dart における Preact Signals
このスキルでは、preact_signals パッケージの中核となるリアクティブプログラミングのプリミティブと実装パターンについて説明します。
関連ドキュメントと項目
| 関連ファイル | 説明 |
|---|---|
| signal.md | 値のアクセサー、変更の仕組み、基本的なカスタムオプションを備えた、標準的な書き込み可能なリアクティブ状態プリミティブです。 |
| computed.md | リアクティブな依存関係を動的に追跡する、遅延評価されるメモ化済みの読み取り専用派生状態シグナルです。 |
| effect.md | 有効なサブスクリプションループ、動的な依存関係の更新、ライフサイクルの終了処理を管理する同期オブザーバーです。 |
| readonly.md | 一方向のデータアクセスを実現する読み取り専用シグナルビューです。 |
| batch.md | リアクティブな計算を最適化し、レンダリングや再計算の頻発を防ぐ、トランザクション形式の状態変更ブロックです。 |
中核プリミティブのクイックスタートガイド
シグナルライブラリは、あらゆるリアクティブなビジネスロジックをモデル化するための構成要素となる、5 つの中核関数を公開しています。
1. signal(initialValue)
新しい可変シグナルコンテナーを作成します。.value にアクセスすると、シグナルの値を読み取ったり、更新を購読したりできます。
final counter = signal(0);
print(counter.value); // 0
counter.value = 1; // Mutates value and schedules dependent updates
.peek()
変更を購読せずに、シグナルの現在値を読み取ります。
final counter = signal(0);
final logCount = signal(0);
effect(() {
print(counter.value);
// Read using peek to avoid subscribing/triggering loop
logCount.value = logCount.peek() + 1;
});
2. untracked(fn)
シグナルを読み取るコールバックを、いずれのシグナルも購読せずに実行します。
final counter = signal(0);
final count = signal(0);
effect(() {
print(counter.value);
count.value = untracked(() => count.value + 1);
});
3. computed(fn)
複数のシグナルの値を組み合わせて、遅延評価されるメモ化済みの派生シグナルを作成します。
final first = signal('John');
final last = signal('Doe');
final fullName = computed(() => '${first.value} ${last.value}');
print(fullName.value); // John Doe
4. effect(fn)
コールバックを実行し、その中で読み取られたシグナルを購読することで、即時かつ同期的な副作用を調整します。
final name = signal('Jane');
final dispose = effect(() => print('Hello $name'));
dispose(); // Clean up subscription
5. batch(fn)
複数のシグナルへの書き込みを単一のトランザクションにまとめ、依存するすべての計算値の評価とエフェクトを最後にそれぞれ 1 回だけ実行します。
final a = signal(0);
final b = signal(0);
batch(() {
a.value = 1;
b.value = 2;
});
1. 中核プリミティブの詳細
A. Signal<T>
監視可能な可変値を表す状態プリミティブです。
final count = signal(0);
count.value = 1; // Notifies all active subscribers/effects
B. Computed<T>
他のシグナルに基づいて計算される読み取り専用の値を表す派生状態プリミティブです。次の特性があります。
- 遅延評価:アクセスされたときにのみ評価されます。
- メモ化:値をキャッシュし、ソースとなる依存関係が変更された場合にのみ再計算します。
final count = signal(2);
final double = computed(() => count.value * 2);
C. Effect
コールバックを直ちに実行し、読み取ったシグナルを追跡するオブザーバーです。追跡対象のシグナルが変更されるたびに再実行されます。
final dispose = effect(() {
print('Current count: ${count.value}');
});
dispose(); // Clean up subscription
2. 依存関係の追跡と再入に関するルール
- 同期コンテキスト:コールバックの実行中にどのシグナルが読み取られたかに基づいて、依存関係が動的に追跡されます。
- 循環の検出:自身の実行フロー内で計算シグナルを読み取ったり、計算コールバック内で依存関係を設定したりすると、循環が発生します。計算ゲッター内で副作用を起こさないでください。
- 遅延初期値:遅延評価される計算シグナルは、作成時には評価されません。再入による循環でクラッシュするのを防ぐため、オブザーバー内で
.peek()を強制的に呼び出す前に、必ずisInitializedを呼び出すか、初期化状態を確認してください。