はじめに
アイスタイルでバックエンドを担当しているkuriyamayです。
前回RxJSの(mergeMap, switchMap, concatMap)について記事を書きました。
今回は他のMapオペレータの使い方についても書いていこうと思います。
前回の記事はこちら
本記事のRxJSはバージョン7.8.1を使用しています
Mapオペレータ
map
値の変換(最も基本的な同期オペレータ)
特徴
- Observable の各値に対して関数を適用し、新しい値に変換する
-
Array.prototype.map
に似ているが、非同期ストリームにも適用できる - RxJS で最も基本的な変換オペレータの1つ
ユースケース
- APIレスポンスを画面用の形式に変換
- 数値や文字列を別の型・オブジェクトに変換
- フロント/バックエンド問わず、ストリーム内のデータ整形に頻出
import { of } from 'rxjs';
import { map } from 'rxjs/operators';
of(1, 2, 3).pipe(
map(value => value * 2)
).subscribe(console.log);
// 出力(mapで各値を2倍に変換)
// 2
// 4
// 6
ポイント
- map は同期的に各値を処理する(非同期処理が必要な場合は mergeMap などを使用)
- 関数の返り値がそのまま次のObservableに流れる
- もっともシンプルな変換処理に使う
exhaustMap
1つ目だけ実行(処理中は新しい入力を無視)
特徴
- 新しい値が来ても、前の処理が完了するまで無視される
- 実行中の inner Observable が完了するまでは、他の入力が すべてスルーされる
-
switchMap
のようなキャンセルもなく、mergeMap
のような並列実行もされない - 多重実行を防ぎたい処理に最適
ユースケース
- ボタンの連打による重複送信を防ぐ(多重APIリクエストの抑止)
- フォーム送信処理の多重実行防止
- ワンクリックで完了すべき処理を確実に1回だけ行いたい場合
import { fromEvent, of } from 'rxjs';
import { exhaustMap, delay } from 'rxjs/operators';
const button = document.getElementById('submit');
fromEvent(button, 'click').pipe(
exhaustMap(() =>
of('Sending request...').pipe(delay(2000)) // 2秒間の処理
)
).subscribe(console.log);
// ボタンを何度クリックしても、2秒の処理中は無視される
// 出力(例):
// Sending request...
// (2秒間無視)
// Sending request...
ポイント
- 実行中の処理がある限り、次の入力は無視される
- switchMap のようにキャンセルされるわけではない(開始されない)
- 多重送信や高負荷な連続処理を避けたい場面で有効
- switchMap の「キャンセル」よりも、「無視する」挙動を求める場面で選ぶ
非推奨オペレータと代替方法
RxJS v7.8.2 では、一部の map 系オペレータが非推奨(deprecated)とされており、代わりに map
を使った記述が推奨されています。
mapTo
- 役割:入力された値を無視して、常に同じ固定値を返すオペレータ
-
代替:
map(() => fixedValue)
-
理由:常に同じ値を返すだけなので、
map
で十分に代替可能
// ❌ mapTo を使って固定値を返す(非推奨)
source$.pipe(mapTo('fixed'))
// ✅ map を使って固定値を返す(推奨)
source$.pipe(map(() => 'fixed'))
map を使えば柔軟なロジックにも対応できます。
pluck
- 役割:オブジェクトから 特定のプロパティの値だけを取り出す オペレータ
-
代替:
map(x => x.prop)
- 理由:pluck('name') はネスト構造に対して型安全でなく、保守性も低い
// ❌ pluck を使ってプロパティを抽出する(非推奨)
source$.pipe(pluck('name'))
// ✅ map を使ってプロパティを抽出する(推奨)
source$.pipe(map(x => x.name))
map を使えばネストされたプロパティにも対応しやすく、TypeScript でも補完が効きます。
まとめ
今回は、RxJS における map
系オペレータの中でも以下の内容を整理しました。
- 基本の
map
は、値を変換する最もシンプルかつ汎用的なオペレータ -
exhaustMap
は、一度に一つだけの処理を確実に行いたいときに有効 -
mapTo
やpluck
は非推奨となっており、代わりにmap(() => value)
やmap(x => x.prop)
の使用が推奨される
RxJSはオペレータが豊富だからこそ、それぞれの役割と違いを正しく理解して使い分けることが重要です。
特に map
は多くのオペレータの基礎となるので、構文に慣れておくと今後の学習がぐっと楽になります。
気になった方は是非RxJSのドキュメントを見てみてください。