Angular Signalsにおける入力変更時のデータフェッチ方法
問題
入力シグナル(input()
)をもつAngularコンポーネントで、シグナルの値が変更された際にデータを再取得する必要があります。従来のngOnChanges
が非推奨方向にある中、Signalsベースのアプローチでの代替方法が不明です。主な課題は次の通りです:
@Component()
export class ChartComponent {
dataSeriesId = input.required<string>();
fromDate = input.required<Date>();
toDate = input.required<Date>();
private data = signal<ChartData | null>(null);
}
computed
は非同期処理をサポートしていないeffect
は状態変更を意図していない(公式ドキュメントで非推奨)- 入力シグナルの変更を検知し
data
シグナルを更新する適切な方法が必要
最新の解決策: Angular 19のrxResource
(推奨)
Angular 19で導入されたrxResource
が最適解です。自動的なキャンセル・ローディング状態処理に対応:
import { rxResource } from "@angular/core/rxjs-interop";
@Component({
template: `
{{ resource.value() }}
@if(resource.isLoading()) { 読み込み中... }
@if(resource.error(); as error) { {{ error }} }
`,
})
export class ChartComponent {
dataSeriesId = input.required<string>();
fromDate = input.required<Date>();
toDate = input.required<Date>();
// 入力値を集約したシグナル
params = computed(() => ({
id: this.dataSeriesId(),
from: this.fromDate(),
to: this.toDate()
}));
// rxResourceでデータ取得を宣言
resource = rxResource({
request: this.params,
loader: (loaderParams) => this.fetchData(loaderParams.request)
});
private fetchData({ id, from, to }: {
id: string; from: Date; to: Date
}) {
return this.http.get<ChartData>(`/api/data`, {
params: { id, from: from.toISOString(), to: to.toISOString() }
});
}
}
特徴
- 自動キャンセル: 新しいリクエスト時に前回リクエストを自動中止
- 状態管理:
value()
,isLoading()
,error()
でUI状態を管理 - 依存追跡: 入力シグナルの変更を自動検知
- Zoneless対応: 変更検知パフォーマンスが最適化
実装上の注意
HttpClient
を利用した場合、再リクエスト時に進行中のHTTPリクエストは自動的にキャンセルされます
動作例: StackBlitz デモ
Angular 19未満での代替案: toObservable
とtoSignal
v19以前ではrxjs-interop
の変換メソッドを利用:
import { toObservable, toSignal } from "@angular/core/rxjs-interop";
@Component()
export class ChartComponent {
// 入力シグナル定義
dataSeriesId = input.required<string>();
fromDate = input.required<Date>();
toDate = input.required<Date>();
// 入力値を集約
params = computed(() => ({
id: this.dataSeriesId(),
from: this.fromDate(),
to: this.toDate()
}));
// Observable ⇆ Signal変換
data = toSignal(
toObservable(this.params).pipe(
switchMap(params => this.fetchData(params))
)
);
private fetchData({ id, from, to }) {
return this.http.get(`/api/data/${id}`, {
params: { from, to }
});
}
}
メリット
- 自動リクエスト発行: 入力値変更を検知し自動実行
- キャンセル処理:
switchMap
で前リクエストを破棄 - シンプルなインターフェース: テンプレート側は
data()
のみ呼出
重要
switchMap
の代わりにmergeMap
を使用すると、リクエスト順序保証されない可能性があります
キャンセル不要な場合はmergeMap
、キャンセル必要ならswitchMap
を選択
非推奨アプローチ: effect
を使った方法
公式ドキュメントで推奨されていませんが、allowSignalWrites
フラグで実装可能:
export class ChartComponent {
// ...入力シグナル
private data = signal<ChartData | null>(null);
private destroyRef = inject(DestroyRef);
constructor() {
let subscription: Subscription;
effect(() => {
subscription?.unsubscribe();
// Signal直接参照で依存関係追跡
const params = {
id: this.dataSeriesId(),
from: this.fromDate(),
to: this.toDate()
};
subscription = this.fetchData(params).subscribe(data => {
this.data.set(data); // 状態更新
});
}, { allowSignalWrites: true }); // 状態変更許可フラグ
// コンポーネント破棄時に購読解除
this.destroyRef.onDestroy(() => subscription.unsubscribe());
}
}
問題点
- 手動購読解除: コンポーネントライフサイクルに対応必要
- キャンセル漏れリスク: 新リクエスト時の旧リクエストキャンセルが手動管理
- エッジケース: 並行リクエスト時の状態競合リスク
回避すること
チームプロジェクトでの不整合リスクが高く、メモリリーク要因となるため特殊なケース以外での使用は避けてください
代替手段が利用できない場合に限り、徹底したテストが必須
パフォーマンスとベストプラクティス
不要な再取得防止
typescript// 無効なパラメータ時はスキップ params = computed(() => { if (!this.dataSeriesId()) return null; return { id: this.dataSeriesId(), from: this.fromDate(), to: this.toDate() }; });
デバウンス処理追加
typescript// 頻繁な変更を抑制 (300msディレイ) data = toSignal( toObservable(this.params).pipe( debounceTime(300), distinctUntilChanged(), switchMap(/* ... */) ) );
エラー処理の標準化
typescriptresource = rxResource({ request: this.params, loader: (p) => this.fetchData(p).pipe( catchError(err => of({ error: err.message, lastValid: this.resource.value() // 旧値を保持 })) ) });
各手法の比較表
特徴 | rxResource (v19+) | toObservable 変換 | effect 利用 |
---|---|---|---|
自動リクエストキャンセル | ○ | ○ (switchMap使用時) | △ (手動管理) |
ローディング状態管理 | ○ | × | × |
エラー処理仕組み | ○ | △ | × |
メモリリークリスク | 低 | 低 | 高 |
コードの簡潔さ | ◎ | ○ | △ |
Angularサポート | 公式推奨 | 互換性対応 | 非推奨 |
結論
Angular v19以上
→rxResource
を積極採用
(最新機能 + 最小コード + 自動管理)Angular v16-v18
→toObservable
+toSignal
+switchMap
が現実解
(安定動作 + リクエストキャンセル対応)どうしても必要な特殊ケース
→effect
のallowSignalWrites
使用(テスト必須)
最新プロジェクトの立ち上げではAngular 19+の採用とrxResource
の活用が、生産性・メンテナンス性の観点で最適解となります。