11
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AngularAdvent Calendar 2024

Day 4

signalの監視を調整する:Angularのuntrackedの基本と実践

Last updated at Posted at 2024-12-03

Angular 16以降では、リアクティブなsignalやエフェクトを使ったアプリケーション開発がより直感的になりました。その中でも「untracked」という機能は、意外と知られていない便利な特性を持っています。

現場で、レビューしていた時、untrackedを初めてみて、気になったので調べてみました!

untrackedとは?

untrackedは、エフェクトの中でsignalの値を取得する際に、値を取得した瞬間に「依存関係」として認識されることを防ぐための関数です。

通常、エフェクトは内部で使用されたsignalを「依存関係」として監視します。これにより、依存関係が更新されるたびにエフェクトが再実行されますが、場合によってはsignalを監視対象から外したいことがあります。このような場面でuntrackedが役立ちます。

例えば以下のケースを考えてみましょう:

  • ボタン1をクリックした際にボタン1のカウントを監視し、ログを出力したい。
  • ただし、その際にボタン2のカウントは監視対象に含めたくない

このような要件を満たすためにuntrackedを使います。

サンプルコードの概要

html
    <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>
typescript
  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. ボタン1とボタン2をクリックして、それぞれのカウントを増加させる。
  2. ボタン1が5回以上クリックされた場合にログを出力する。
  3. このとき、untrackedを使用すると、ボタン2のカウントはログ出力のトリガーには影響を与えません。

実行時の挙動は次のセクションに記載します。

実行結果を見てみよう

untrackedを使用した場合

ボタン1を5回クリック(GIFは6回押下してます)するとログが出力されますが、ボタン2をクリックしてもログの再実行は発生しません。これは、untrackedによってボタン2のカウントがエフェクトの監視対象から外れたためです。

untracked.gif

コメントアウトを外した場合

untrackedをコメントアウトして、ボタン2の値を直接参照するとどうなるでしょうか?
ボタン1の条件を満たしている状態でボタン2をクリックするたびにログが出力されます。この挙動は、untrackedを使用していないため、ボタン2も監視対象に追加された結果です。

untracked-not.gif

untrackedを使うべきシーンとは?

  • エフェクト内でsignalを参照したいが、監視対象にしたくない場合。
  • 一時的な値の参照やデバッグ情報の取得時。
  • パフォーマンスや不要な再実行の抑制が求められる場合。

最後に

Angularのリアクティブシステムでは、untrackedを使うことでエフェクトの挙動を柔軟に制御できます。このシンプルな機能を理解して活用することで、より効率的で意図通りに動作するアプリケーションを構築できます。ぜひ自分のプロジェクトでも試してみてください!

明日は、@kazumeatさんです!

11
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?