RxJSの基本を簡単な計算アプリで身につけよう

# はじめに

Angularでアプリを開発し始めたとき、RxJSの概念には本当に戸惑いました。「オブザーバブル」「サブジェクト」「オペレータ」という言葉の意味がわからず、コードを書くのに苦労しました。でも実際に使ってみると、非同期処理やイベント処理がとても簡潔に書けるようになり、その威力を実感しました。

# RxJS

RxJSは非同期処理を扱うためのライブラリです。その大きな特徴は、すべてを**データの流れ**として考えることです。ユーザーのクリック、HTTPリクエスト、時間の経過など、あらゆる出来事をデータの流れとして統一的に扱います。

これにより、複雑な非同期処理を簡潔に書けるようになり、特にAngularアプリケーションでの開発効率が大幅に向上します。

# 実装

### コンポーネントの作成
```bash
ng generate component reduce-demo
```

### TypeScript
```typescript
import { Component, OnInit } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { map, Subject } from 'rxjs';
@Component({
  selector: 'app-reduce-demo',
  standalone: true,
  imports: [FormsModule, CommonModule],
  templateUrl: './reduce-demo.component.html',
  styleUrl: './reduce-demo.component.css'
})
export class ReduceDemoComponent implements OnInit {
  // 入力フィールドの値
  numbersInput = '';
  // 変換後の数値配列
  numbers: number[] = [];
  // 計算結果
  sum = 0;
  // RxJSのSubject - イベントを発行するためのオブジェクト
  private inputSubject = new Subject<string>();
  ngOnInit() {
    // RxJSのパイプラインを設定
    this.inputSubject.pipe(
      // 文字列を数値配列に変換
      map((input: string) => {
        // 例: input = "1, 2, 3"
        return input
          .split(',')                        // ["1", " 2", " 3"]
          .map((n) => Number(n.trim()))      // [1, 2, 3]
          .filter((n) => !isNaN(n));         // 無効な値を除外
      }),
      // 合計を計算
      map(numbers => {
        // 例: numbers = [1, 2, 3]
        this.numbers = numbers;              // 配列を保存
        
        // 合計計算
        return numbers.length > 0
          ? numbers.reduce((acc, curr) => acc + curr, 0)
          : 0;
      })
    ).subscribe(sum => {
      // 例: sum = 6
      this.sum = sum;                        // 結果を保存
    });
  }
  // 入力イベントハンドラ
  processInput() {
    // 入力値をSubjectに送信
    this.inputSubject.next(this.numbersInput);
  }
}
```

### HTML
```html
<div class="container">
  <h2>RxJSを使ったリアクティブな計算</h2>
  
  <!-- 入力フォーム -->
  <div class="input-section">
    <label for="numbers">数値をカンマ区切りで入力してください:</label>
    <input 
      id="numbers" 
      type="text" 
      [(ngModel)]="numbersInput"
      (input)="processInput()"
      placeholder="例: 1,2,3,4,5"
    />
  </div>
  <!-- 結果表示 -->
  <div class="results" *ngIf="numbers.length > 0">
    <h3>結果:</h3>
    <p>入力された数値: {{ numbers.join(', ') }}</p>
    <p>合計: {{ sum }}</p>
  </div>
</div>
```

# RxJSの主要概念と実装解説

初心者にとって難しいRxJSの概念を、計算アプリの実装を通して説明します。

### オブザーバブル

オブザーバブルは**水が流れる川**のようなものです。データが時間とともに流れていきます。この実装では、ユーザー入力の変化が川の流れになっています。入力が変わるたびに、新しいデータが流れていきます。

```typescript
// Subjectはオブザーバブルの一種です
private inputSubject = new Subject<string>();

// パイプラインの設定（この中をデータが流れていきます）
this.inputSubject.pipe(
  map(...),
  map(...)
)
```

この例では、`inputSubject` がオブザーバブルとして機能し、パイプラインを通じてデータが流れていきます。ユーザーが入力フィールドに何かを入力するたびに、そのデータがオブザーバブルに流れ込み、パイプラインで処理されていきます。

### サブジェクト

サブジェクトは水源と川の両方の性質を持つものです。水を供給することも、水を流すこともできます。この実装では、`inputSubject` がサブジェクトとして機能しています。

```typescript
private inputSubject = new Subject<string>();
```

ユーザーが入力フォームに何かを入力すると、`processInput()`メソッドが呼び出され、`inputSubject.next()`でデータを発行します。これは川に水を流す（データを送り出す）ようなものです。

```typescript
processInput() {
    // 入力値をSubjectに送信
    this.inputSubject.next(this.numbersInput);
}
```

また、サブジェクトにはパイプラインが接続されており、流れてきた水（データ）を受け取って処理もします。

### オペレータ

オペレータは**川に設置されたフィルター**のようなものです。流れてくる水（データ）を受け取って、形を変えて次に流します。

この実装では、`map`オペレータを使用しています。最初の`map`は入力された文字列をカンマで分割し、数値の配列に変換するフィルターです。2番目の`map`はその数値配列を合計値に変換するフィルターです。

例えば、ユーザーが `1,2,3` と入力すると、

最初の`map`でデータは `"1,2,3"` から `[1,2,3]` に変換されます

```typescript
map((input: string) => {
  return input
    .split(',')
    .map((n) => Number(n.trim()))
    .filter((n) => !isNaN(n));
})
```

2番目の`map`でデータは `[1,2,3]` から `6` に変換されます

```typescript
// 合計を計算
map(numbers => {
    // 例: numbers = [1, 2, 3]
    this.numbers = numbers;              // 配列を保存

    // 合計計算
    return numbers.length > 0
      ? numbers.reduce((acc, curr) => acc + curr, 0)
      : 0;
})
```

### サブスクライブ

```typescript
.subscribe(sum => {
  this.sum = sum;
});
```

サブスクライブは**川の下流に立って、流れてくる水（データ）を受け取ります。**

この実装では、`subscribe`メソッドがその役割を果たしています。パイプラインの最後で変換されたデータ（この場合は合計値）を受け取り、それを使って画面を更新します。ユーザーが `1,2,3` と入力した場合、最終的に `6` という値がサブスクライブの部分に届き、その値が`this.sum`に保存されてUIに表示されます。

# まとめ

この記事では、RxJSの基本である「オブザーバブル」「サブジェクト」「オペレータ」「サブスクライブ」を簡単な計算アプリで学びました。

RxJSは最初は難しく感じますが、データの流れとして考えれば理解しやすくなります。まずは小さなアプリから始めて、少しずつ慣れていきましょう。RxJSを使いこなせば、より簡潔で保守しやすいコードが書けるようになります。

説明が不十分な点や疑問に思う部分があれば、お気軽にご指摘ください。RxJSについて一緒に理解を深められたら幸いです。