Angular 16以降では、リアクティブなsignalやエフェクトを使ったアプリケーション開発がより直感的になりました。その中でも「untracked
」という機能は、意外と知られていない便利な特性を持っています。
現場で、レビューしていた時、untracked
を初めてみて、気になったので調べてみました!
untracked
とは?
untracked
は、エフェクトの中でsignalの値を取得する際に、値を取得した瞬間に「依存関係」として認識されることを防ぐための関数です。
通常、エフェクトは内部で使用されたsignalを「依存関係」として監視します。これにより、依存関係が更新されるたびにエフェクトが再実行されますが、場合によってはsignalを監視対象から外したいことがあります。このような場面でuntracked
が役立ちます。
例えば以下のケースを考えてみましょう:
- ボタン1をクリックした際にボタン1のカウントを監視し、ログを出力したい。
- ただし、その際にボタン2のカウントは監視対象に含めたくない。
このような要件を満たすためにuntracked
を使います。
サンプルコードの概要
<div class="container">
<h2>ボタンカウンター</h2>
<div class="button-group">
<button mat-raised-button color="primary" (click)="incrementButton1()">
ボタン1
</button>
<p>ボタン1が押された回数: {{ button1Count() }}</p>
</div>
<div class="button-group">
<button mat-raised-button color="accent" (click)="incrementButton2()">
ボタン2
</button>
<p>ボタン2が押された回数: {{ button2Count() }}</p>
</div>
<div class="log-info">
<p>ログ出力回数: {{ logCount() }}</p>
</div>
</div>
button1Count = signal(0);
button2Count = signal(0);
logCount = signal(0);
constructor() {
effect(
() => {
const count1 = this.button1Count();
if (count1 >= 5) {
const count2 = untracked(() => this.button2Count());
// const count2 = this.button2Count();
console.log(
`#ボタン1ログ送信:ボタン1が5回を超えました(${count1}回), ボタン2の現在値: ${count2}回`
);
this.logCount.update((count) => count + 1);
}
},
{ allowSignalWrites: true }
);
}
incrementButton1() {
this.button1Count.update((count) => count + 1);
}
incrementButton2() {
this.button2Count.update((count) => count + 1);
}
- ボタン1とボタン2をクリックして、それぞれのカウントを増加させる。
- ボタン1が5回以上クリックされた場合にログを出力する。
- このとき、
untracked
を使用すると、ボタン2のカウントはログ出力のトリガーには影響を与えません。
実行時の挙動は次のセクションに記載します。
実行結果を見てみよう
untracked
を使用した場合
ボタン1を5回クリック(GIFは6回押下してます)するとログが出力されますが、ボタン2をクリックしてもログの再実行は発生しません。これは、untracked
によってボタン2のカウントがエフェクトの監視対象から外れたためです。
コメントアウトを外した場合
untracked
をコメントアウトして、ボタン2の値を直接参照するとどうなるでしょうか?
ボタン1の条件を満たしている状態でボタン2をクリックするたびにログが出力されます。この挙動は、untracked
を使用していないため、ボタン2も監視対象に追加された結果です。
untracked
を使うべきシーンとは?
- エフェクト内でsignalを参照したいが、監視対象にしたくない場合。
- 一時的な値の参照やデバッグ情報の取得時。
- パフォーマンスや不要な再実行の抑制が求められる場合。
最後に
Angularのリアクティブシステムでは、untracked
を使うことでエフェクトの挙動を柔軟に制御できます。このシンプルな機能を理解して活用することで、より効率的で意図通りに動作するアプリケーションを構築できます。ぜひ自分のプロジェクトでも試してみてください!
明日は、@kazumeatさんです!