🌟

httpClientのリクエストを、httpResourceに書き換える

に公開

httpResource、便利ですね。Signalベースになっていて、リクエスト内部で使っているSignalが書き換わる度に、リクエストを実行します。個人的には、 Resource.reload() がお気に入りです。おそらくほとんどのAngularユーザが、httpリクエストはService経由に行っており、以下のようなコードを書いていたと思います。

@Injectable({...})
export class ExampleService {
  readonly #http = inject(HttpClient);
  
  // Promiseベースで取り回している場合
  getDataPromise(id: string): Promise<Data> {
    return firstValueFrom(this.#http.get<Data>(environment.api + 'example/' + id));
  }

  // Observableベース
  getDataObservable(id: string): Observable<Data> {
    return this.#http.get<Data>(environment.api + 'example/' + id);
  }
}

これを、async pipeを使ってテンプレートに直接反映させていたのか、コンポーネントのプロパティに代入して反映してたのかはそれぞれですが、長らく見慣れたコードでしょう。それが、以下のように書けるようになりました。

@Injectable({...})
export class ExampleService {
  readonly #http = inject(HttpClient);
  
  // Promiseベースで取り回している場合
  getData(id: Signal<string>): HttpResourceRef<Data> {
    return httpResource<Data>(environment.api + 'example/' + id());
  }
}

これを、直接コンポーネントのプロパティにバインディングします。

@Component({...})
export class ExamplePage {
  readonly id = input.required<number>();
  readonly #exampleService = inject(ExampleService);
  readonly dataResource = this.#exampleService.getData(this.id);
}

注意することは、Signalから値を取り出すのではなく、Signalごと引数に渡すことぐらいでしょうか。ライフサイクルに左右されず、Signalの値ベースでリクエストがハンドリングできるの、シンプルでめちゃくちゃいいですよね。おすすめです。

Ionic Angularだと、実際のコードは以下のようになります(ViewDidEnterプロパティは https://zenn.dev/rdlabo/articles/bb03d724d33831 をご参考ください)

@Component({...})
export class ExamplePage {
  readonly id = input.required<number>();
  readonly el = inject(ElementRef);
  readonly #didEnter = toSignal(createDidEnter(this.el));
  readonly #exampleService = inject(ExampleService);
  readonly dataResource = this.#exampleService.getData(this.#didEnter, this.id);
}
@Injectable({...})
export class ExampleService {
  readonly #http = inject(HttpClient);
  
  getData(didEnter: Signal<boolean>, id: Signal<string>): HttpResourceRef<Data> {
    return httpResource<IMovie[]>(() => {
      if (!didEnter()) {
        return undefined;
      }
      return environment.api + 'example/' + id();
    });
  }
}

以前と比べて随分シンプルに書けるようになりましたね。まだ実験中のAPIですが、ぜひお試しくださいー!

Discussion