Dev Study
← 解説「inject() — サービスを受け取る」に戻る

サンプルコードで身につける: inject() — サービスを受け取る

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

1サービスを受け取って呼び出す

inject() の最小例で、フィールドの初期化として書くとDIコンテナ管理のインスタンスが手に入ります。new LoggerService() と自分で作っていないことが最大のポイントです。受け取ったあとは this.logger.log() と普通のメソッド呼び出しで使えます。

import { Component, inject } from '@angular/core';
import { LoggerService } from './logger.service';

@Component({
  selector: 'app-save-button',
  template: '<button (click)="save()">保存</button>',
})
export class SaveButtonComponent {
  // new せず、フィールドの初期化として inject() で受け取る
  private logger = inject(LoggerService);

  save() {
    this.logger.log('保存ボタンが押されました');
  }
}

2サービスのシグナルをテンプレートで読む

inject したサービスが持つシグナルは、テンプレートから cart.count() とそのまま読めます。テンプレートで使うフィールドは private にしない、という実務上の注意も含んだ例です。ヘッダーのカートアイコンの件数表示は、まさにこの構成で作られます。

import { Component, inject } from '@angular/core';
import { CartStateService } from './cart-state.service';

@Component({
  selector: 'app-cart-icon',
  // サービスのシグナルをテンプレートからそのまま読める
  template: '<span>カート({{ cart.count() }})</span>',
})
export class CartIconComponent {
  // テンプレートから使うので private にしない
  cart = inject(CartStateService);
}

3複数のサービスを組み合わせる

必要なサービスの数だけ inject() を並べる、実務で最もよく見る形です。カートへの追加とログ記録という別々の関心事を、それぞれの専門サービスに任せています。コンストラクタ注入と違って引数の順番を気にする必要がなく、行を追加するだけで済むのが inject() の利点です。

import { Component, inject } from '@angular/core';
import { CartStateService } from './cart-state.service';
import { LoggerService } from './logger.service';

@Component({
  selector: 'app-add-to-cart',
  template: '<button (click)="add()">カートに入れる</button>',
})
export class AddToCartComponent {
  // 必要なサービスはクラスの先頭でまとめて受け取る
  private cart = inject(CartStateService);
  private logger = inject(LoggerService);

  add() {
    this.cart.add('コーヒー豆');
    this.logger.log('カートに商品を追加した');
  }
}

4サービスの中で別のサービスを使う

inject() はコンポーネント専用ではなく、サービスの中でもまったく同じ書き方で使えます。注文処理のサービスがログのサービスを利用する、というサービス同士の連携の例です。コンストラクタ注入では親子で引数を引き回す手間がありましたが、inject() ならどこでも1行で済みます。

import { Injectable, inject } from '@angular/core';
import { LoggerService } from './logger.service';

@Injectable({ providedIn: 'root' })
export class OrderService {
  // サービスの中でも inject() は同じ書き方で使える
  private logger = inject(LoggerService);
  private orderedItems: string[] = [];

  order(itemName: string) {
    this.orderedItems.push(itemName);
    this.logger.log(itemName + ' を注文しました');
  }
}

5お気に入りボタンを完成させる

前レッスンで設計した FavoriteService を inject し、input で受け取った商品IDと組み合わせる実務的な完成形です。ボタンの表示はサービスの判定結果で切り替わり、状態の本体はサービスが一元管理しています。「状態はサービス、操作と表示はコンポーネント」という役割分担の集大成です。

import { Component, inject, input } from '@angular/core';
import { FavoriteService } from './favorite.service';

@Component({
  selector: 'app-favorite-button',
  // サービスの判定結果で表示を切り替える
  template:
    '<button (click)="toggle()">' +
    '@if (favorites.has(productId())) { ★ 登録済み } @else { ☆ お気に入りに追加 }' +
    '</button>',
})
export class FavoriteButtonComponent {
  favorites = inject(FavoriteService);
  productId = input.required<number>();

  toggle() {
    this.favorites.toggle(this.productId());
  }
}