🔄

Angular Signalsで状態管理がめちゃくちゃ楽になった話

に公開

Angular Signalsで状態管理がめちゃくちゃ楽になった話

Angular Signals、最高ですよね。状態管理がめちゃくちゃ楽になりました。これまでReduxとかNgRxとか使ってたけど、正直めんどくさかったんですよね。Signalsを使うようになってから、状態管理の考え方が根本から変わりました。

時間の概念から解放された

RxJSでよくやってた「いつ」状態が変わるかという考え方から解放されました。例えば、こんなコード:

// 昔の書き方(RxJS)
const counter$ = new BehaviorSubject(0);
counter$.pipe(
  debounceTime(300),
  distinctUntilChanged()
).subscribe(value => {
  // 値が変化したときの処理
});

// 今の書き方(Signals)
const counter = signal(0);
effect(() => {
  // counterの値が変化するたびに自動的に実行される
  console.log(counter());
});

RxJSだと「いつ」状態が変わるかを意識する必要がありましたが、Signalsでは「何が」状態であるかだけを考えればよくなりました。これ、めちゃくちゃ楽です。

状態管理の煩わしさから解放された

ReduxとかNgRxとか使ってたときは、アクション、リデューサー、セレクターとか、めちゃくちゃボイラープレートコード書いてましたよね。Signalsでは、こんな感じでシンプルに書けます:

// 基本的なSignalsの例
const count = signal(0);
const doubledCount = computed(() => count() * 2);
const isEven = computed(() => count() % 2 === 0);

// 状態の更新
count.update(value => value + 1);

状態管理の「管理」という部分が、Signalsによって自動化されました。開発者は、状態が「何であるか」を定義するだけでよくなりました。

実践的な例:カウンターアプリ

実際のコードを見てみましょう。こんな感じで書けます:

import { Component } from '@angular/core';
import { signal, computed, effect } from '@angular/core';

@Component({
  selector: 'app-counter',
  template: `
    <div>
      <h2>カウンター: {{ count() }}</h2>
      <p>2倍の値: {{ doubledCount() }}</p>
      <p>{{ isEven() ? '偶数です' : '奇数です' }}</p>
      <button (click)="increment()">増加</button>
      <button (click)="decrement()">減少</button>
      <button (click)="reset()">リセット</button>
    </div>
  `,
})
export class CounterComponent {
  // ソースデータ
  count = signal(0);
  
  // 派生データ
  doubledCount = computed(() => this.count() * 2);
  isEven = computed(() => this.count() % 2 === 0);
  
  // 副作用
  constructor() {
    effect(() => {
      console.log(`カウントが変更されました: ${this.count()}`);
    });
  }
  
  // アクション
  increment() {
    this.count.update(value => value + 1);
  }
  
  decrement() {
    this.count.update(value => value - 1);
  }
  
  reset() {
    this.count.set(0);
  }
}

これ、めちゃくちゃシンプルですよね。状態管理のコードが減って、ビジネスロジックに集中できるようになりました。

一方向のデータフロー

Signalsを使うと、データが一方向に流れるようになります。例えば:

// ソースデータ(アプリケーションの状態の源)
const sourceData = signal({ user: null, items: [] });

// 派生データ
const user = computed(() => sourceData().user);
const items = computed(() => sourceData().items);
const hasItems = computed(() => items().length > 0);

// UIの状態
const isLoading = signal(false);
const selectedItemId = signal(null);
const selectedItem = computed(() => {
  const id = selectedItemId();
  return id ? items().find(item => item.id === id) : null;
});

これ、デバッグがめちゃくちゃ楽になりました。データの流れが明確で、どこで問題が起きているかがすぐにわかります。

まとめ

Signalsを使ってみて、以下の点が特に良かったです:

  1. 時間の概念からの解放 - RxJSの「いつ」から解放されて、コードがすっきり
  2. 状態管理の煩わしさからの解放 - Reduxとかのボイラープレートコードから解放
  3. シンプルなデータパイプライン - Signalsのネットワークで状態を表現できる
  4. 一方向のデータフロー - デバッグが楽になった
  5. 関数としての関係性 - UIは状態の関数、状態はデータの関数という考え方

小〜中規模のアプリケーションでは、NgRxなどの大きなライブラリを導入せずとも、Signalsだけで十分対応できそうです。これからもSignalsを使い倒していきたいと思います!

それでは、また。

Discussion