0Pricing
Angular Academy · レッスン

サービス内のSignal Store

Signalベースのサービスでアプリの状態を保持します

「サービス内のSignal Store」はCoddyKit上の無料Angular Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAngular Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Angular Academyコースには全4レッスンが含まれています。

状態としてのシグナル

Angularのシグナルは、変化したときに利用側へ通知するリアクティブな値です。シグナルは値を保持し、それを読み取る計算やテンプレートを再実行します。

@Injectableサービス内にシグナルを保持すると、複数のコンポーネントで同じリアクティブな状態を共有できます。

最小限のシグナルストア

サービスを作成し、signal()に状態を保持します。書き込み可能なシグナルは非公開にし、読み取り専用のビューを公開します。

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

@Injectable({ providedIn: 'root' })
export class CounterStore {
  private _count = signal(0);
  readonly count = this._count.asReadonly();

  increment() { this._count.update(c => c + 1); }
}

providedIn rootの理由

providedIn: 'root'にすると、サービスはアプリ全体でシングルトンになります。これを注入するすべてのコンポーネントがまったく同じシグナルインスタンスを共有するため、状態の同期が保たれます。

シグナルの読み取り

シグナルを関数として呼び出すと値を読み取れます。テンプレート内では、Angularが読み取りを追跡し、値が変化するとDOMを自動的に更新します。

import { Component, inject } from '@angular/core';
import { CounterStore } from './counter.store';

@Component({
  selector: 'app-counter',
  template: '<button (click)="store.increment()">{{ store.count() }}</button>'
})
export class CounterComponent {
  store = inject(CounterStore);
}

asReadonlyによる状態の保護

asReadonly()は、読み取りはできますが書き込みはできないシグナルを返します。コンポーネントから誤ってset()やupdate()を呼び出せないため、すべての変更がストアのメソッドを経由します。

setとupdateの違い

次の値が直接分かっている場合はset(value)を使います。次の値が現在の値に依存する場合はupdate(fn)を使います。

private _user = signal<User | null>(null);

setUser(u: User) { this._user.set(u); }
clearUser() { this._user.set(null); }
touch() { this._user.update(u => u ? { ...u, seen: true } : u); }

1つのストアに複数のシグナル

ストアには、状態の異なる部分を表す複数のシグナルを保持できます。各書き込み可能なシグナルを非公開にし、対応する読み取り専用のシグナルを公開します。

private _items = signal<Item[]>([]);
private _loading = signal(false);

readonly items = this._items.asReadonly();
readonly loading = this._loading.asReadonly();

メソッドによるロジックのカプセル化

ビジネスルールはコンポーネントではなく、ストアのメソッドに置きます。コンポーネントはaddToCart(item)のように意図が分かるメソッドを呼び出し、状態をどう変更するかはストアが決定します。

addToCart(item: Item) {
  this._items.update(list => [...list, item]);
}
removeFromCart(id: string) {
  this._items.update(list => list.filter(i => i.id !== id));
}

サブスクリプション不要

RxJSベースのサービスとは異なり、シグナルストアではsubscribe()も手動の購読解除も必要ありません。テンプレートでシグナルを読み取るだけでリアクティブな処理が接続され、コンポーネントが破棄されるとAngularが後処理します。

inject()による注入

inject()関数は、コンストラクター、フィールド初期化子、ファクトリ関数で使用できます。ストアのインスタンスを取得する現代的な方法です。

export class CartComponent {
  private store = inject(CartStore);
  items = this.store.items; // read-only signal
}

シグナルストアのテスト

シグナルストアは通常のクラスなので、テストは簡単です。インスタンスを作成し、メソッドを呼び出して、シグナルの値を同期的に読み取ります。非同期処理の準備は必要ありません。

it('increments', () => {
  const store = new CounterStore();
  store.increment();
  expect(store.count()).toBe(1);
});

確認問題

シグナルストアについての理解を確認します。

まとめ

書き込み可能なシグナルを非公開にし、asReadonly()のビューを公開し、メソッド内でsetやupdateを使って状態を変更し、inject()でシングルトンを注入する、シグナルベースのストアの構築方法を学びました。サブスクリプションは不要で、テストも簡単な共有リアクティブ状態を実現できます。

よくある質問

「サービス内のSignal Store」レッスンは無料ですか?

はい。「サービス内のSignal Store」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Angular Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Angular Academyコースには全4レッスンが含まれています。

「サービス内のSignal Store」で何を学びますか?

Signalベースのサービスでアプリの状態を保持します ブラウザで直接実行するハンズオンコードでAngular Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Angular Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのAngular Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「サービス内のSignal Store」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このAngular Academyレッスンでコードを書いて実行できますか?

はい。すべてのAngular Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. サービス内のSignal Store
  2. computedによる状態の導出
  3. イミュータブルな状態更新
  4. SignalsとRxJSの接続
← Angular Academyに戻る