サンプルコードで学ぶObservableとSubjectの実践例

2024-04-16

RxJSにおけるObservableとSubjectの違い

Observableは、時間経過とともに値を発行するデータストリームを表します。データソースからのイベント通知、センサーデータの読み取り、APIからのレスポンスなど、様々なユースケースで利用できます。Observableはプッシュ型であり、購読者にデータをプッシュ配信します。

一方、Subjectは、ObservableとObserverの両方の特性を持つ特殊な型です。値を発行するだけでなく、購読者からの値も受け取ることができます。Subjectは双方向型であり、データの流れを双方向に制御できます。

以下、ObservableとSubjectの主な違いをまとめます。

項目ObservableSubject
データの流れプッシュ型双方向型
値の発行可能可能
値の購読可能可能
値の送信購読者にプッシュ配信購読者にプッシュ配信または購読者から受け取り発行
作成方法Observable.create(), from(), of() などnew Subject()

具体的なユースケースとしては、以下のようなものが挙げられます。

  • Observable: ネットワークリクエストのレスポンス、フォーム入力イベント、タイマーイベントなど、一方方向のデータストリームを扱う場合
  • Subject: ログイン/ログアウト処理、チャットアプリケーション、双方向のデータ通信など、双方向のデータ制御が必要な場合

ObservableとSubjectは、どちらもRxJSにおける重要な概念ですが、それぞれ異なる性質と役割を持っています。それぞれの特性を理解し、適切な場面で使用することが重要です。




RxJSにおけるObservableとSubjectのサンプルコード

Observable

import { Observable, of } from 'rxjs';
import { subscribe } from 'rxjs/operators';

const observable = of(1, 2, 3);

observable.pipe(
  subscribe(value => console.log('Observable value:', value))
)

このコードでは、of関数を使って値 1, 2, 3 を発行するObservableを作成します。そして、subscribeオペレーターを使ってObservableを購読し、発行された値をコンソールに出力します。

Subject

import { Subject } from 'rxjs';

const subject = new Subject();

subject.next(0);
subject.subscribe(value => console.log('Subject value:', value));
subject.next(1);
subject.next(2);

このコードでは、new Subject()を使ってSubjectを作成します。そして、nextメソッドを使ってSubjectに値 0, 1, 2 を発行します。また、subscribeオペレーターを使ってSubjectを購読し、発行された値をコンソールに出力します。

上記コードを実行すると、以下の出力が得られます。

Observable value: 1
Observable value: 2
Observable value: 3
Subject value: 0
Subject value: 1
Subject value: 2

Observableは、値を発行した後に購読しても、発行された過去の値は取得できません。一方、Subjectは、購読後でも発行されたすべての値を取得することができます。

以下のサンプルコードでは、ObservableとSubjectのより具体的なユースケースを紹介します。

ネットワークリクエストのレスポンスを扱う

import { Observable, fromEvent } from 'rxjs';
import { map } from 'rxjs/operators';

const fetchButton = document.getElementById('fetch-button');

const observable = fromEvent(fetchButton, 'click').pipe(
  map(() => fetch('https://jsonplaceholder.typicode.com/todos/1'))
);

observable.subscribe(response => {
  response.json().then(data => console.log('Todo:', data));
});

このコードでは、ボタンクリックイベントをObservableに変換し、ボタンクリック時にAPIリクエストを送信します。そして、APIレスポンスを購読し、取得したTodoデータをコンソールに出力します。

フォーム入力イベントを扱う

import { Observable, fromEvent } from 'rxjs';
import { debounceTime, map } from 'rxjs/operators';

const input = document.getElementById('search-input');

const observable = fromEvent(input, 'input').pipe(
  debounceTime(300),
  map(event => event.target.value)
);

observable.subscribe(query => console.log('Search query:', query));

このコードでは、入力フィールドの入力イベントをObservableに変換し、入力値の変化を300ms後に発行します。そして、入力値を購読し、コンソールに出力します。

チャットアプリケーションを構築する

import { Subject } from 'rxjs';

const chatSubject = new Subject();

const chatInput = document.getElementById('chat-input');
const chatList = document.getElementById('chat-list');

chatInput.addEventListener('input', (event) => {
  const message = event.target.value;
  chatSubject.next(message);
  event.target.value = '';
});

chatSubject.subscribe(message => {
  const listItem = document.createElement('li');
  listItem.textContent = message;
  chatList.appendChild(listItem);
});

このコードでは、Subjectを使ってチャットアプリケーションを構築します。入力フィールドに入力されたメッセージをSubjectに発行し、チャットリストに表示します。

ObservableとSubjectは、RxJSにおける強力なツールです。それぞれの特性を理解し、適切な場面で使用することで、より柔軟で効率的なアプリケーション開発が可能になります。




RxJSにおけるObservableとSubjectのその他の使い分け

既存のデータストリームを処理する場合、Observableが適しています。例えば、APIレスポンス、イベントストリーム、ファイル読み込みなど、外部ソースから提供されるデータストリームを処理したい場合に有効です。

例:

import { Observable, fromEvent } from 'rxjs';
import { map } from 'rxjs/operators';

const button = document.getElementById('my-button');

const observable = fromEvent(button, 'click').pipe(
  map(event => event.target.textContent)
);

observable.subscribe(text => console.log('Button clicked:', text));

双方向のデータ通信を行う場合、Subjectが適しています。例えば、フォーム入力、チャットアプリケーション、リアルタイムデータ更新など、双方向でデータの送受信が必要な場合に有効です。

import { Subject } from 'rxjs';

const subject = new Subject();

subject.subscribe(value => console.log('Received value:', value));

subject.next('Hello!');
subject.next('World!');

値を共有する

複数のコンポーネント間で値を共有する場合、Subjectが適しています。例えば、複数のコンポーネントで同じデータを参照する必要がある場合や、コンポーネント間でイベントを発行・購読する必要がある場合に有効です。

import { Subject } from 'rxjs';

const counterSubject = new Subject();

const counterComponent = {
  template: `
    <button (click)="increment()">Increment</button>
    <span>Count: {{ count }}</span>
  `,
  data() {
    return {
      count: 0,
    };
  },
  methods: {
    increment() {
      this.count++;
      counterSubject.next(this.count);
    },
  },
};

const logComponent = {
  template: `
    <span>Current count: {{ count }}</span>
  `,
  data() {
    return {
      count: 0,
    };
  },
  mounted() {
    counterSubject.subscribe(count => (this.count = count));
  },
};

値をバッファリングする場合、ReplaySubjectが適しています。例えば、遅延が発生する可能性のあるデータストリームを処理する場合や、購読後に発行された過去の値を取得したい場合に有効です。

import { ReplaySubject } from 'rxjs';

const replaySubject = new ReplaySubject(2);

replaySubject.next(1);
replaySubject.next(2);
replaySubject.next(3);

replaySubject.subscribe(value => console.log('Received value:', value));

replaySubject.next(4);

最後の値のみを発行する場合、AsyncSubjectが適しています。例えば、データストリームが完了したときに最後の値を取得したい場合に有効です。

import { AsyncSubject } from 'rxjs';

const asyncSubject = new AsyncSubject();

asyncSubject.next(1);
asyncSubject.next(2);
asyncSubject.next(3);

asyncSubject.subscribe(value => console.log('Received value:', value));

asyncSubject.complete();

ObservableとSubjectは、それぞれ異なる性質と役割を持つため、適切な場面で使用することが重要です。上記の例を参考に、それぞれの使い分けを理解し、より柔軟で効率的なアプリケーション開発を目指しましょう。


javascript angular rxjs


初心者向け!JavaScriptでUnixタイムスタンプを理解し、操作する

JavaScriptには、日付や時刻を扱うためのDateオブジェクトが用意されています。Dateオブジェクトを使って、Unixタイムスタンプを以下の手順で時間に変換できます。**new Date()**を使って新しいDateオブジェクトを作成します。...


Node.jsによるファイル内の文字列置換:初心者から上級者向け

Node. jsを使って、ファイル内の特定の文字列を別の文字列に置換することは可能です。この操作には、主に2つの方法があります。方法1: fs モジュールと String. prototype. replace() メソッドを使うfs モジュールをインポートします。...


TypeScript、Angular、Angular2-Routing を使った非同期認証

Angular2 の canActivate() 関数は、ルートガードやコンポーネントガードとして使用され、ユーザーが特定のルートやコンポーネントにアクセスできるかどうかを制御します。従来、canActivate() 関数は同期的に実行されていましたが、Angular2 では非同期関数を呼び出すことも可能です。これは、認証やデータフェッチなどの非同期操作が必要な場合に役立ちます。...


【初心者向け】Angularで要素にスタイルを適用する方法:スタイルバインディング、ngStyle、スタイル属性、コンポーネントスタイル、CSS変数

[class] バインディング: 単一のクラスを条件に応じて追加・削除します。それぞれの詳細と使い分けについて、以下で分かりやすく解説します。構文:説明:classExpression は、真偽値を返す式です。式が true の場合、指定されたクラスが要素に追加されます。...


JavaScript、Angular、TypeScriptで「Property 'entries' does not exist on type 'ObjectConstructor'」エラーが発生したときの解決策

このエラーは、JavaScript、Angular、TypeScriptでオブジェクトのentries()メソッドを使用しようとした際に発生します。entries()メソッドは、オブジェクトのキーと値のペアをイテレータとして返すために使用されます。...