こんにちは!
Angularでアプリケーションを開発していると、HTTPリクエストで取得したデータを加工して表示したい場面が頻繁に訪れます。そんなとき、RxJSのpipeとmapオペレーターの組み合わせが非常に役立ちます。
pipeの中でmapを使うって、具体的にどう書けばいいの?
subscribeの中で全部処理するのと何が違うんだろう?
AngularでRxJSを使い始めたばかりのころ、このような疑問を持つことは自然なことです。
この記事では、Angularにおけるpipeメソッドとmapオペレーターの使い方について、それぞれの役割から実践的な使用方法、そしてテンプレートとの連携までを詳しく解説します。
この記事は次のような方におすすめです。
- AngularでRxJSの
pipeとmapの基本的な使い方を学びたい方 - HTTPリクエストで取得したデータを加工する方法を知りたい方
subscribeだけで処理を書くコードから脱却したい方asyncパイプと組み合わせてテンプレートをシンプルにしたい方- RxJSの基礎をしっかりと固めたいAngular開発者の方
この記事を読めば、pipeとmapの役割が明確に理解でき、実際のプロジェクトですぐに応用できる知識が身につきます。RxJSの強力な機能を活用して、よりクリーンで保守性の高いコードを書けるようになりましょう。
「データの変換処理をスマートに書きたい方」や「Angularのコードレビューで良い評価を得たい方」は、ぜひ最後までお付き合いください。
それでは、順を追って詳しく見ていきましょう!
Angularにおけるpipeとは何か
まずはじめに、Angularで「pipe」という言葉が使われるとき、実は2つの異なる概念を指していることを理解しておく必要があります。
1つ目は、Angularテンプレートで使用する「パイプ」です。これはDatePipeやCurrencyPipeのように、テンプレート内で{{ value | date }}という形式で使われるもので、表示データを変換するための機能です。
2つ目は、RxJSのpipeメソッドです。こちらはObservableに対して使用するメソッドで、複数のオペレーターを組み合わせてデータストリームを処理するためのものです。この記事で扱うのは、このRxJSのpipeメソッドの方になります。
RxJSのpipeメソッドは、Observableから流れてくるデータに対して、複数の処理を順番に適用するためのメソッドです。mapやfilterといったオペレーターをpipeの中に渡すことで、データを段階的に変換していくことができます。
pipeメソッドの基本的な特徴は以下の通りです。
- Observableのメソッドとして呼び出します。
- 複数のオペレーターをカンマ区切りで渡すことができます。
- オペレーターは左から右へ順番に実行されます。
- 元のObservableは変更されず、新しいObservableが返されます。
このpipeメソッドを使うことで、データの変換処理を可読性高く、保守しやすい形で記述できます。
RxJSのmapオペレーターとは何か
mapオペレーターは、Observableから流れてくる各値に対して変換処理を行い、変換後の値を流す新しいObservableを作成するためのオペレーターです。
JavaScriptの配列に対するmapメソッドと同じような働きをしますが、mapオペレーターは配列ではなく、Observableから時間とともに流れてくる値に対して処理を適用します。
mapオペレーターの基本的な特徴は以下の通りです。
- Observableから流れてくる各値を1つずつ受け取ります。
- 受け取った値に対して変換処理を適用します。
- 変換後の値を流す新しいObservableを返します。
- 元のObservableのストリームは変更されません。
例えば、数値のストリームに対してmapを使えば、各数値を2倍にしたり、文字列に変換したりすることができます。同様に、HTTPリクエストで取得したオブジェクトから、必要なプロパティだけを抽出することも可能です。
pipeとmapの基本的な使い方
それでは、実際にpipeとmapを組み合わせて使う方法を見ていきましょう。
最もシンプルな例として、数値のストリームを変換する処理を書いてみます。
import { Component, OnInit } from '@angular/core';
import { of } from 'rxjs';
import { map } from 'rxjs/operators';
@Component({
selector: 'app-example',
template: `<p>結果はコンソールで確認してください</p>`
})
export class ExampleComponent implements OnInit {
ngOnInit() {
// 1, 2, 3を順番に流すObservableを作成
const numbers$ = of(1, 2, 3);
// pipeとmapを使って各値を2倍に変換
numbers$.pipe(
map(value => value * 2)
).subscribe(result => {
console.log(result); // 2, 4, 6と出力される
});
}
}
このコードでは、of(1, 2, 3)で作成したObservableに対してpipeメソッドを呼び出し、その中でmapオペレーターを使っています。map(value => value * 2)の部分で、流れてくる各値を2倍に変換しています。
実際にAngularアプリケーションでは、このような単純な数値変換よりも、HTTPリクエストで取得したデータの加工によく使われます。
Angular HTTPClientでのpipe map の使用例
Angularでは、サーバーとの通信にHttpClientを使います。HttpClientのメソッドはObservableを返すため、pipeとmapを組み合わせてレスポンスデータを加工することが一般的です。
例えば、ユーザー情報を取得するAPIがあるとして、レスポンスの中から必要なデータだけを抽出する場合を見てみましょう。
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
interface User {
id: number;
name: string;
email: string;
}
@Injectable({
providedIn: 'root'
})
export class UserService {
constructor(private http: HttpClient) {}
getUser(id: number): Observable<string> {
return this.http.get<User>(`/api/users/${id}`).pipe(
map(user => user.name)
);
}
}
このコードでは、http.getが返すObservable<User>に対してpipeとmapを適用し、Userオブジェクト全体ではなく、nameプロパティだけを抽出したObservable<string>を返しています。
これにより、このサービスを利用するコンポーネント側では、Userオブジェクト全体を受け取る必要がなくなり、シンプルに名前の文字列だけを扱えるようになります。
レスポンスデータの変換パターン
HTTPリクエストで取得したデータをpipeとmapで加工する際、よく使われるパターンをいくつか紹介します。
パターン1 特定のプロパティを抽出する
APIレスポンスから必要なプロパティだけを取り出す最もシンプルなパターンです。
getUserName(id: number): Observable<string> {
return this.http.get<User>(`/api/users/${id}`).pipe(
map(user => user.name)
);
}
パターン2 複数のプロパティを新しいオブジェクトにまとめる
レスポンスから複数のプロパティを選択して、新しい形のオブジェクトを作成します。
getUserInfo(id: number): Observable<{ userName: string; userEmail: string }> {
return this.http.get<User>(`/api/users/${id}`).pipe(
map(user => ({
userName: user.name,
userEmail: user.email
}))
);
}
パターン3 ネストされたデータから値を取り出す
APIレスポンスがネストした構造を持つ場合、深い階層から必要なデータを取り出すことができます。
interface ApiResponse {
data: {
user: User;
};
}
getUser(id: number): Observable<User> {
return this.http.get<ApiResponse>(`/api/users/${id}`).pipe(
map(response => response.data.user)
);
}
これらのパターンを使うことで、コンポーネント側では加工済みのデータをそのまま利用できるため、コードがシンプルになります。
複数のmapオペレーターを組み合わせる
pipeメソッドの中では、複数のオペレーターをカンマで区切って順番に並べることができます。これにより、データを段階的に変換していくことが可能です。
getUserDisplay(id: number): Observable<string> {
return this.http.get<User>(`/api/users/${id}`).pipe(
map(user => user.name),
map(name => name.toUpperCase()),
map(upperName => `ユーザー名: ${upperName}`)
);
}
この例では、3つのmapオペレーターを順番に適用しています。
- 1つ目の
mapでUserオブジェクトから名前を抽出します。 - 2つ目の
mapで名前を大文字に変換します。 - 3つ目の
mapで「ユーザー名: 」という接頭辞を付けた文字列を作成します。
このように、pipeの中で複数の変換処理を順番に記述することで、複雑な処理を段階的に分解して書くことができます。結果として、コードの可読性が向上し、各変換処理の役割が明確になります。
asyncパイプとの連携
Angularテンプレートには、Observableを直接扱える便利なasyncパイプがあります。pipeとmapで加工したObservableをasyncパイプと組み合わせることで、テンプレート側のコードを非常にシンプルにできます。
まず、コンポーネント側でpipeとmapを使ってデータを加工したObservableを用意します。
import { Component } from '@angular/core';
import { Observable } from 'rxjs';
import { AsyncPipe } from '@angular/common';
@Component({
selector: 'app-user-display',
standalone: true,
imports: [AsyncPipe],
template: `
<div>
<p>ユーザー名: {{ userName$ | async }}</p>
</div>
`
})
export class UserDisplayComponent {
userName$: Observable<string>;
constructor(private userService: UserService) {
this.userName$ = this.userService.getUserName(1);
}
}
このコードでは、userName$というObservableをテンプレートでasyncパイプを使って展開しています。asyncパイプを使うことで、コンポーネント側でsubscribeを呼ぶ必要がなくなり、購読の管理も自動的に行われます。
pipeとmapで加工したObservableをテンプレートで直接扱えるため、コンポーネントクラスのコードがシンプルになり、メモリリークのリスクも減らすことができます。
subscribeとの違いを理解する
RxJSを学び始めたとき、多くの開発者がsubscribeの中で全ての処理を書いてしまいがちです。しかし、データの変換処理はpipeとmapで行い、最終的な結果を受け取るときだけsubscribeを使うのが推奨されるパターンです。
良くないパターンを見てみましょう。
// 推奨されない書き方
this.http.get<User>(`/api/users/${id}`).subscribe(user => {
const name = user.name;
const upperName = name.toUpperCase();
const display = `ユーザー名: ${upperName}`;
this.displayText = display;
});
このコードには以下のような問題があります。
- データの変換処理がsubscribeの中に書かれており、再利用できません。
- テストが書きにくくなります。
- asyncパイプと組み合わせることができません。
推奨される書き方は、変換処理をpipeとmapに分離することです。
// 推奨される書き方
this.displayText$ = this.http.get<User>(`/api/users/${id}`).pipe(
map(user => user.name),
map(name => name.toUpperCase()),
map(upperName => `ユーザー名: ${upperName}`)
);
この書き方では、変換処理がpipeの中に明確に定義されており、テンプレートでasyncパイプを使って簡単に表示できます。また、必要に応じて他の場所でも再利用可能です。
ひとつひとつ真摯に向き合う企業
株式会社 ONE WEDGEでは、新たな仲間を募集しています!
私たちと一緒に、革新的で充実したキャリアを築きませんか?
当社は、従業員が仕事と私生活のバランスを大切にできるよう、充実した福利厚生を整えています。
- 完全週休2日制(土日休み)で、祝日や夏季休暇、年末年始休暇もしっかり保証!
- 様々な休暇制度(有給、慶弔、産前・産後、育児、バースデー休暇、有給6日取得で特別休暇付与)を完備!
- 従業員の成長と健康を支援するための表彰制度、資格取得支援、健康促進手当など!
- 生活を支えるテレワーク手当、記事寄稿手当、結婚祝金・出産祝金など、様々な手当を提供!
- 自己啓発としての書籍購入制度や、メンバー間のコミュニケーションを深める交流費補助!
- 成果に応じた決算賞与や、リファラル採用手当、AI手当など、頑張りをしっかり評価!
- ワークライフバランスを重視し、副業もOK!
株式会社 ONE WEDGEでは、一人ひとりの従業員が自己実現できる環境を大切にしています。
共に成長し、刺激を与え合える仲間をお待ちしております。
あなたの能力と熱意を、ぜひ当社で発揮してください。
ご応募お待ちしております!
ホームページ、採用情報は下記ボタンからご確認ください!
応募、ご質問など、お問い合わせフォーム、またはX (旧Twitter)、InstagramのDMでお気軽にご相談ください♪
まとめ
Angularにおけるpipeメソッドとmapオペレーターの使い方について解説しました。
pipeはObservableに対して複数のオペレーターを適用するためのメソッドです。mapはObservableから流れてくる各値を変換するオペレーターです。- HTTPリクエストのレスポンスデータを加工する際に、
pipeとmapの組み合わせが非常に有効です。 - 複数の
mapを組み合わせることで、段階的にデータを変換できます。 asyncパイプと組み合わせることで、テンプレート側のコードがシンプルになります。- データの変換処理は
pipeとmapで行い、最終結果の取得だけをsubscribeで行うのが推奨されるパターンです。
これらの知識を実践することで、あなたのAngularコードはより読みやすく、保守しやすいものになります。ぜひ、実際のプロジェクトでこれらのテクニックを活用してみてください。
※本記事の本文案はAIを活用して作成していますが、記載しているコードは筆者が実際に実行・検証し、内容の正確性を確認したうえで公開しています。

