Dev Study
← Angular コース

54. 提供範囲 — root提供とコンポーネント提供

サービスのインスタンスが「どの範囲で1個か」は、どこで提供するかで決まります。@Injectable({ providedIn: 'root' }) はアプリ全体で1個の共有インスタンスです。一方、コンポーネントの providers: [CounterService] に書くと、そのコンポーネントが作られるたびに専用のインスタンスが作られ、その部品ツリーの中だけで共有されます。

使い分けの指針は「基本は root、画面ごとに独立した状態が欲しいときだけコンポーネント提供」です。たとえば同じ検索パネルを1画面に2つ置き、それぞれが別々の検索状態を持つべきなら、状態サービスをパネル側の providers に置きます。root のままだと2つのパネルが同じ状態を共有してしまいます。

つまずきやすいのは、コンポーネント提供にしたことを忘れて「別の画面で値が消えた」と混乱するケースです。コンポーネント提供のインスタンスは、そのコンポーネントが破棄されると一緒に消えます。逆に root のサービスは画面を離れても生き続けるので、状態の寿命をどちらにしたいかで選びましょう。

サンプルコード(フレームワーク環境が必要なため表示のみ)

import { Component, Injectable, inject } from '@angular/core';

// providedIn を付けない = 提供場所を providers で決めるサービス
@Injectable()
export class CounterService {
  count = 0;
  increment() {
    this.count++;
  }
}

@Component({
  selector: 'app-counter-panel',
  // このコンポーネントごとに専用のインスタンスが作られる
  providers: [CounterService],
  template:
    '<button (click)="counter.increment()">+1</button>' +
    ' <span>{{ counter.count }}</span>',
})
export class CounterPanel {
  counter = inject(CounterService);
}

// <app-counter-panel /> を2つ並べると、カウントは別々に進む
サンプルコードで身につける(5本) →

学んだ概念を、素朴な例から実務寄りの例まで5つの具体例で確認します。

公式ドキュメントで詳しく ↗