こんにちは、開発部の鈴木です。
今回は、Angularアプリケーションの開発における、サービスの提供方法と利用範囲について紹介します。
モジュールも関わってくるので、前回紹介したモジュール設計についての記事も参考にしてみてください!

サービスとは

サービスとは、アプリケーションのロジックやデータを扱うためのクラスです。
Angularでは基本的に、コンポーネントが画面の表示を担当し、サービスがその他の処理を担当するように設計します。

サービスの提供

サービスは依存性の注入によって、コンポーネントや他のサービスなどから利用されます。
AngularはInjectorを用いて依存性の注入を行い、それによって利用範囲やライフサイクルが異なるいくつかの階層を指定してサービスを提供することができます。
今回はルート階層、モジュール階層、エレメント階層の3つの階層によるサービスの提供方法と、それぞれの違いについて紹介します。

ここで紹介するコードのサンプルはこちらを参照してください。

ルート階層

ルート階層でサービスを提供するためには、サービスのクラス定義に@Injectable()を追加し、providedInプロパティにrootを指定します。

@Injectable({
  providedIn: 'root',
})
export class RootService {
}

ルート階層でサービスを提供すると、そのサービスはアプリケーション全体で利用することができます。

このサービスは、初めて利用されるタイミングでインスタンスが作成され、アプリケーションの終了時に破棄されます。

モジュール階層

モジュール階層でサービスを提供するためには、サービスのクラス定義に@Injectable()を追加します。
また、サービスを利用したいモジュールのprovidersにそのサービスの定義を追加します。

@Injectable()
export class FeatureService {
}
@NgModule({
  ...
  providers: [FeatureService],
})
export class FeatureModule {}

モジュール階層でサービスを提供すると、そのサービスは指定したモジュール内(子孫のモジュールを含む)でのみ利用することができます。

このサービスもルート階層のサービスと同様に、初めて利用されるタイミングでインスタンスが作成され、アプリケーションの終了時に破棄されます。

エレメント階層

エレメントとはコンポーネントやディレクティブのことを指し、今回はコンポーネントを例に説明します。

エレメント階層でサービスを提供するためには、サービスのクラス定義に@Injectable()を追加します。
また、サービスを利用したいコンポーネントのprovidersにそのサービスの定義を追加します。

@Injectable()
export class ElementService {
}
@Component({
  ...
  providers: [ElementService],
})
export class ElementComponent {
}

エレメント階層でサービスを提供すると、そのサービスは指定したコンポーネント内(子孫のコンポーネントを含む)でのみ利用することができます。

このサービスは、コンポーネントが作成されたタイミングでインスタンスが作成され、そのコンポーネントが破棄されるとサービスのインスタンスも破棄されます。

まとめ

以上で、サービスの提供方法と利用範囲、それに伴うライフサイクルの違いについて説明しました。

サービスの利用範囲やライフサイクルを理解して設計することは、ソースコードの可読性や保守性を向上させることに直結します。
また、画面実装における複雑な状態管理を、少しでもシンプルにすることに役立つと思います!

おわりに

今回紹介した内容を実装したものが下記のサンプルで動かすことができるので、よければ試してみてください。