Skip to content

Angularの新しい制御フロー構文: NgForから@forへの移行

Angular 17では、新しい制御フロー構文が導入され、従来の*ngFor@forに置き換えられています。この変化はパフォーマンスの向上と開発者エクスペリエンスの改善を目的としています。

問題の要点

  • Angular 17で*ngForが非推奨となり@forが推奨される
  • 構文の違いにより初期学習コストが発生する可能性
  • 既存プロジェクトの移行方法と新構文のメリットが不明確

@forの基本構文と利点

typescript
// 基本構文
@for (item of items; track item.id) {
  {{ item.name }}
}

// 空リスト処理
@for (item of items; track item.id) {
  <p>{{ item.name }}</p>
} @empty {
  <p>アイテムがありません</p>
}

主な特徴と優位性

  1. 追跡キーの必須化によるパフォーマンス改善:

    • trackキーの指定が必須に
    • 変更検出が効率化され、DOM操作が最小限に
    typescript
    // 従来 (*ngFor)
    *ngFor="let item of items; trackBy: trackById"
    
    // 新しい構文 (@for)
    @for (item of items; track item.id)
  2. 空リストの宣言的処理:

    • @emptyブロックで空状態を直接処理可能
    • 追加の条件分岐が不要に
  3. バンドルサイズの削減:

    • ランタイムコードの生成が軽量化
    • スタンドアロンコンポーネントでDirectiveのインポートが不要
  4. 開発者エクスペリエンスの向上:

    • テンプレートの可読性向上
    • 型推論の精度向上(TypeScriptサポート)

実用的なアドバイス

trackには常にユニークな識別子を使用しましょう。オブジェクトIDがある場合はtrack item.id、ない場合はtrack indexが有効です:

typescript
@for(user of users; track user.id) { ... }  // 推奨
@for(user of users; track $index) { ... }   // 代替案

パフォーマンス比較

特徴@for*ngFor
変更追跡ビルトイン(必須)trackBy(任意)
バンドルサイズ〜15%削減基準サイズ
レンダリング速度最大20%高速化基準速度
空状態処理@emptyブロックサポートngIfなど別途実装が必要

移行ガイド

  1. Angular CLIコマンドでの一括変換:

    bash
    ng generate @angular/core:control-flow
  2. 手動移行ステップ:

    html
    <!-- 変換前 -->
    <div *ngFor="let item of items">
      {{ item.name }}
    </div>
    
    <!-- 変換後 -->
    @for (item of items; track item.id) {
      <div>{{ item.name }}</div>
    }

注意点

  • Angular 16未満での互換性なし
  • 一部サードパーティライブラリが追いついていない可能性

ケーススタディ: 実際の使用例

typescript
// コンポーネント
cars = [
  { id: 1, model: 'Toyota Camry', year: 2022 },
  { id: 2, model: 'Honda Civic', year: 2023 }
];

// テンプレート
<select>
  @for (car of cars; track car.id) {
    <option [value]="car.id">{{car.model}} ({{car.year}})</option>
  } @empty {
    <option disabled>利用可能な車種がありません</option>
  }
</select>

よくある質問

Q: *ngForは完全に廃止されますか?
A: 当面は互換性を維持しますが、新規開発では@forの使用が推奨されます

Q: 複合条件でのリストフィルタリングは?
A: メソッド呼び出しが推奨されます:

typescript
@for (item of filteredItems(); track item.id) {
  ...
}

// コンポーネント内
filteredItems() {
  return this.items.filter(item => item.active);
}

参考リソース

新しい制御フロー構文は、パフォーマンスと開発効率の両面で大きな進歩をもたらします。初期の構文変更に対する抵抗感は理解できますが、長期的なメリットを考慮すれば移行の価値があります。