🕌

AngularのwithComponentInputBindingでルーティングパラメータを扱う

に公開

Angular v17で導入された withComponentInputBinding とSignal Inputの組み合わせにより、ルーティングパラメータの扱いが劇的に改善されました。この記事では、従来の方法から新しい方法への移行パターンを紹介します。(超今更な記事ではありますが、マイグレーションを後回しにしてたプロジェクトがあって、生成AIに参考情報として食べさせるために書きました)

従来の方法と新しい方法の比較

1. ActivatedRouteからparamsを取得する方法

ActivatedRoute から params を得るためには、 paramMap をsubscribeするか、snapshot.paramMap から得るかの2つのパターンがありました。

従来の方法

@Component({
  // ...
})
export class UserDetailComponent implement OnInit {
  userId: string;
  route = inject(ActivatedRoute);

  ngOnInit() {
    // Pattern paramMap
    this.route.paramMap.subscribe(params => {
      this.userId = params['id'];
    });

    // Pattern snapshot
    this.userId = this.route.snapshot.paramMap.get('id');
  }
}

新しい方法

withComponentInputBinding を使うと、以下のようにシンプルに書くことができます。この機能は、以下の情報をコンポーネントの入力に直接バインドします:

  • クエリパラメータ
  • パスパラメータとマトリックスパラメータ
  • 静的ルートデータ
  • リゾルバーからのデータ
@Component({
  // ...
})
export class UserDetailComponent {
  userId = input<string>();
}

2. paramsMapをsubscribeして他の処理をしている場合

paramsMap が変更する度に、それにあわせて他の処理をしていた場合もあるかと思います。

従来の方法

@Component({
  // ...
})
export class UserDetailComponent implement OnInit {
  route = inject(ActivatedRoute);
  userService = inject(UserService);
  userId: string;
  userData: IUser;

  ngOnInit() {
    this.route.paramMap.subscribe(params => {
      this.userId = params.get('id')!;
      this.loadUserData();
    });
  }

  private loadUserData() {
    this.userService.getUser(this.userId).subscribe(data => {
      this.userData = data;
    });
  }
}

新しい方法

その場合は、Signals で入ってくることを活かして effect で処理を行います。また、ルートデータに一致するキーがない場合、入力は undefined に設定されることに注意が必要です。これは、ルートからデータが削除された場合(クエリパラメータが削除された場合など)に、以前の情報が保持されるのを防ぐためです。

@Component({
  // ...
})
export class UserDetailComponent {
  route = inject(ActivatedRoute);
  userService = inject(UserService);
  userId = input<string>();
  userData: IUser;

  constructor() {
    effect(() => {
      const id = this.userId();
      if (id) {
        this.userService.getUser(id).subscribe(data => {
          this.userData = data;
        });
      }
    })
  }
}

新しい方法の利点

従来の方法では ActivatedRoute の注入と subscribe が必要でしたが、新しい方法では Signal Input だけで済むようになりました。これにより、コードがより宣言的になり、型安全性も向上します。

また、Signal Input を使用することで、コンポーネントの入力が単純になり、テストが書きやすくなります。特に、ルーティングパラメータの変更に応じて他の処理を行う場合、effect を使用することで、より宣言的なコードを書くことができます。

まとめ

withComponentInputBinding とSignal Inputの組み合わせにより、ルーティングパラメータの扱いが大幅に改善されました。コードが簡潔になり、型安全性も向上し、パフォーマンスも改善されるという、まさに一石三鳥の機能です。

新しいプロジェクトではもちろん、既存のプロジェクトでも段階的に移行を検討する価値があるでしょう。特に、複雑なルーティングパラメータの処理を行っているコンポーネントでは、その効果を実感できるはずです。

Discussion