【RxJS】BehaviorSubject

`BehaviorSubject`でのデータ共有について、前提としてSubjectの理解もあった方が分かりやすかったため、併せて整理します。

## Subjectとは
- `Subject`は`Observable`による値の購読と`Observer`による値を受け取り実行する、両方の機能を持つオブジェクト。
- `Observable`では`Observer`にユニキャストで値を送信していたが、`Subject`では`Observer`にマルチキャストで値を送信できる。
- `Subject`では`Observable`にてコンシューマーに値を送信していた`subscriber`関数が不要。

### Observable（ユニキャスト）
```ts
import { Observable } from 'rxjs';

const observable = new Observable(subscriber => {
  subscriber.next("hoge");
  subscriber.next("fuga");
  subscriber.next("piyo");
});

observable.subscribe({
  next: (v) => console.log(`observer1: ${v}`),
});

observable.subscribe({
  next: (v) => console.log(`observer2: ${v}`),
});

// 表示 (observer1,observer2が直列で実行される)
// observer1: hoge
// observer1: fuga
// observer1: piyo
// observer2: hoge
// observer2: fuga
// observer2: piyo
```
### Subject（マルチキャスト）
```ts
import { Subject } from 'rxjs';

const subject = new Subject<string>();

subject.subscribe({
  next: (v) => console.log(`observer1: ${v}`),
});

subject.subscribe({
  next: (v) => console.log(`observer2: ${v}`),
});

subject.next("hoge");
subject.next("fuga");
subject.next("piyo");

// 表示 (observer1,observer2が並列で実行される)
// observer1: hoge
// observer2: hoge
// observer1: fuga
// observer2: fuga
// observer1: piyo
// observer2: piyo
```

## BehaviorSubjectとは
- `Subject`の機能に加え、最後に更新された値を保持することができるオブジェクト。
- コンストラクタにより初期値を設定することもできる。
- 値を保持することができるため、コンポーネント間でデータ共有も可能。

```ts
import { BehaviorSubject } from 'rxjs';

// 初期値を0で設定
const subject = new BehaviorSubject(0);

subject.subscribe({
  next: (v) => console.log(`observer1: ${v}`),
});

subject.next(1);
subject.next(2);

subject.subscribe({
  next: (v) => console.log(`observer2: ${v}`),
});

subject.next(3);

// 表示
// observer1: 0
// observer1: 1
// observer1: 2
// observer2: 2 ※最新の値を保持しているため、observer2は値2が送信された後でも受信できる
// observer1: 3
// observer2: 3
```

### 値を別コンポーネントで共有する場合
#### 各ファイルの役割
- app.service.ts
  - 初期値の設定
  - 値の更新
- app.component.ts
  - 値の購読 
- app.component.html
  - 値の表示 

serviceの`BehaviorSubject`を変更すると別コンポーネントでも値が更新されます。

```app.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class AppService {
　// 初期値の設定
  public name = new BehaviorSubject<string>("test");
  constructor() { }

  changeName(name: string): void {
    // 値の更新
    this.name.next(name);
  }
}
```

```app.component.ts
import { Component, OnInit } from '@angular/core';
import { AppService } from './app.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit{
  public name: string = "";

  constructor(private appService: AppService) {}

  ngOnInit(){
    // 値の購読
    this.appService.name.subscribe(name => {
      this.name = name;
    });
  }

  changeName(name: string): void {
    this.appService.changeName(name);
  }
}
```
``` app.component.html
<!-- 値の表示 -->
<p>{{name}}</p> 
<input type="text" #newName>
<button (click)="changeName(newName.value)">名前変更</button>
```


# 参考
- [Subject](https://rxjs-dev.firebaseapp.com/guide/subject)
- [AngularのBehaviorSubjectでコンポーネント間の情報を共有する](https://blog.webcreativepark.net/2018/07/14-215935.html)
- [Observable × Subject/BehaviorSubject × それぞれの使い方を調べてみた](https://www.kinakomotitti.net/entry/2021/08/22/190213)