← 解説「untracked — 依存に数えずにシグナルを読む」に戻る
サンプルコードで身につける: untracked — 依存に数えずにシグナルを読む
解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。
1依存に入る読み方・入らない読み方
effectの中でのシグナルの読み方は2通りあります。普通に読めば依存に登録され、untrackedで包めば登録されません。まずこの対比を最小の形で確認します。
import { signal, effect, untracked } from '@angular/core';
const a = signal(1);
const b = signal(10);
effect(() => {
const valueA = a(); // 依存に入る
const valueB = untracked(() => b()); // 依存に入らない
console.log(valueA, valueB);
});
a.set(2); // → effect が再実行される
b.set(20); // → 何も起きない(依存ではないから)
2ログ送信のきっかけを1つに絞る
ページ遷移のログを送るeffectで、ユーザー名も本文に含めたいケースです。untrackedが無いと、ユーザー名の変更でも「遷移していないのにログが飛ぶ」誤動作になります。
import { Component, signal, effect, untracked, inject } from '@angular/core';
import { AnalyticsService } from './analytics.service';
@Component({ selector: 'app-tracker', template: '' })
export class TrackerComponent {
private analytics = inject(AnalyticsService);
page = signal('home');
userName = signal('kazu');
constructor() {
effect(() => {
const page = this.page(); // きっかけはページ遷移だけ
const name = untracked(() => this.userName());
this.analytics.send({ page, name });
});
// userName.set('matsumoto') してもログは飛ばない
}
}
3computed の中でも使える
untrackedはeffect専用ではなく、computedの中でも同じように働きます。「件数が変わったときだけメッセージを作り直したい。文面に使う名前の変更では作り直さなくてよい」という例です。
import { signal, computed, untracked } from '@angular/core';
const count = signal(3);
const userName = signal('kazu');
const message = computed(() => {
const n = count(); // これが変われば再計算
const name = untracked(() => userName()); // 参考情報
return `${name} さん、未読が ${n} 件あります`;
});
console.log(message()); // 'kazu さん、未読が 3 件あります'
userName.set('matsumoto');
console.log(message()); // 変わらない(再計算されていない)
count.set(5);
console.log(message()); // 'matsumoto さん、未読が 5 件あります'
4シグナルを読む関数ごと包む
untrackedには関数をまるごと渡せます。中で他のシグナルを読んでいるサービスのメソッドを呼ぶとき、意図しない依存が紛れ込むのを防げます。「このeffectのきっかけは selectedId だけ」と明確に宣言できます。
import { effect, untracked } from '@angular/core';
// cart.summary() は内部で items() や coupon() を読んでいるとする
effect(() => {
const id = this.selectedId(); // きっかけはこれだけ
untracked(() => {
// この中でいくつシグナルが読まれても依存には入らない
const summary = this.cart.summary();
this.logger.log(`選択 ${id} 時点のカート: ${summary}`);
});
});
5乱用すると更新されない画面になる
untrackedの使いすぎは「値を変えたのに反映されない」という一番調べにくいバグを生みます。派生値の計算に使う値は素直に依存させるのが原則です。悪い例と直した例を比べます。
// ── 悪い例: 表示に使う値を untracked にしてしまった ──
// total = computed(() => {
// const price = untracked(() => this.price()); // ×
// return price * this.quantity();
// });
// → price を変えても合計が画面に反映されない!
// ── 直した例: 計算に使う値は普通に読む ──
// total = computed(() => this.price() * this.quantity());
// 原則: untracked は「ログ・計測・通知」など、
// 画面の表示に関わらない副作用の参考情報にだけ使う