インフラジスティックス・ジャパン株式会社Blog

インフラジスティックス・ジャパン株式会社のチームメンバーが技術トレンド、製品Tips、サポート情報からライセンス、日々の業務から感じることなど、さまざまなトピックについてお伝えするBlogです。

Angular Signals を理解する:総合ガイド

進化し続けるWeb開発の世界において、Angularはプログラマーの能力を絶え間なく強化することで、常に最前線を走り続けています。同社は、改善への揺るぎないコミットメントで知られており、今回のAngular v16のリリースではエキサイティングな新機能である『 Angular Signals 』を導入しました。

Angular Signalsが初めての方、またはすでに開発者プレビューを試したことがあるがSignalの仕組みについて詳しく知りたい方に、この包括的なガイドが理解の助けとなるでしょう。

Angular Signalsとは? & なぜ今すぐその使い方を学ぶことが重要なのか?

基本的に、Angular Signalsは、引数がゼロの関数 [(() => T)] として機能するリアクティブモデルです。それはどのように動作するのでしょうか?ここで重要なポイントは、ゲッター関数です。ゲッター関数の呼び出しにより、現在の値が返されます。そして、Angularは依存関係が変更されたときにこれらのリアクティブ値を自動的に認識して更新します。

このプロセスを視覚化するための図を次に示します。

これにより、モデルを更新するとAngularは対応するビューに変更を自動的に適用します。これにより、シームレスで同期されたモデルとビューのインタラクションが可能になり、最終的にはスムーズなUXを実現します。

Angular SignalsはObserverデザインパターンに基づいているため、値とそれに関心のあるサブスクライバーのリストを格納するパブリッシャーがあります。値が変更されると、サブスクライバーに通知が届き、更新が必要な箇所が分かります。つまり、変更があった箇所だけを更新すればよいため、Angularがコンポーネントツリー全体の変更をチェックする必要がなくなります。これにより、過度に複雑な操作を避けることができます。

この機能の大きな利点の一つは、状態値の更新を簡略化し、レンダリングパフォーマンスを最適化できることです。これを使用することで、開発者は状態の変更をきめ細かく制御しながら、以下のようなメリットを得ることができます。

  • 自動依存関係追跡: Angular は、リアクティブ値を自動的に認識して更新します。
  • 簡単な状態更新: 最小限の複雑さで状態の変更をきめ細かく制御できます。
  • 遅延評価される計算値: 要なときにのみ計算が行われるため、効率的です。
  • きめ細かな状態追跡: 状態の変更を詳細に追跡できます。
  • コンポーネントの外部にシグナルを実装可能: Dependency Injectionで問題なく動作します。
  • 変更検出の改善: Angularの変更検出メカニズムが効率化されます。
  • アプリのパフォーマンスと保守性の向上: アプリケーション全体のパフォーマンスが向上し、保守が容易になります。

Angular Signals vs RxJS

これらのすべての機能により、多くの人がAngular SignalsをRxJS(Reactive Extensions for JavaScript)と同じくらい強力であると考えていますが、その構文はよりシンプルです。これはRxJSにとって何を意味するのでしょうか?その運命は決まっているのでしょうか?私の意見ではそうではありません。この新機能は、手動でのサブスクリプション管理やメモリリークのリスクなど、RxJSの複雑さの一部を隠すことができるかもしれませんが、すぐにRxJSに取って代わるものではありません。

この新機能の重要性を強調し、その定義を示しました。次に、Angularでシグナルを作成し、使用する方法について説明します。

ハンズオン: Angular Signals 入門

3つのプリミティブを検証し、それらがどのように機能し、それぞれをいつ使用するかを示します。

前提条件:

  • Angular の経験があること。
  • フレームワークのリアクティブ原則に関する基本的な知識。
  • Angular 16 バージョンがインストールされ、実行されていること。

まず最初に、この新しい機能は、「Writable Signals」「Computed Signals」「Effects」の3つのリアクティブプリミティブを提供し、Angularアプリでリアクティブ性を実現します。

Writable Signals の使用

書き込み可能なシグナルは直接更新できるシグナルで、使用するには最初に定義する必要があります。次に技術的なデモンストレーションを示します。

Import { signal } from@angular/core’;
const count = signal(0);
Count.set(count() +1);

Computed Signals の使用

Computed Signalsを使用すると、派生値を処理するための宣言型メソッドが得られます。関数が依存するシグナルのいずれかに変更があった場合、計算されたシグナルは再計算され、読み取り専用の派生シグナルが生成されます。次に技術的なデモンストレーションを示します。

import { computed, signal } from '@angular/core';
 const count = signal(0);
const doubled = computed(() => count() * 2);

Effects の使い方

Angular Signalsのエフェクトは、Signalの変更に応じて機能を実行します。effect() 内では、状態を命令的に変更したり、DOMを手動で変更したり、非同期コードを実行したりできます。次に技術的なデモンストレーションを示します。

import { effect, signal } from '@angular/core';
const count = signal(0);
effect(() => {
  console.log('Count changed to:', count());
});
count.set(1);

Angular Signals の例

ここでは、Angular Signals の動作を確認するための実用的な例を示します。3つのプリミティブすべてを使用して、単純なカウンターアプリケーションを作成しましょう。

import { Component } from '@angular/core';
import { signal, computed, effect } from '@angular/core';
 
@Component({
  selector: 'app-counter',
  template: `
    <div>
      <button (click)="increment()">Increment</button>
      <p>Count: {{ count() }}</p>
      <p>Doubled: {{ doubled() }}</p>
    </div>
  `
})
export class CounterComponent {
  count = signal(0);
  doubled = computed(() => this.count() * 2);
 
  constructor() {
    effect(() => {
      console.log('Count changed to:', this.count());
    });
  }
 
  increment() {
    this.count.set(this.count() + 1);
  }
}

Angular Signals と Ignite UI: 何が含まれていますか?

『 Angular Signals 』と 『 Ignite UI for Angular 』を組み合わせると、Web アプリケーションを次のレベルに引き上げることができます。ここでは、この強力なコンボがどのように機能するかを簡単に説明します。Angular Signals は、変更を正確に追跡することで状態管理を簡素化し、Ignite UI は堅牢で高性能な UI コンポーネントを提供します。これらを組み合わせることで、アプリの高速化と応答性が向上します。

次に、Angular Signals と Ignite UI を使用してリアルタイムのデータ グリッドを構築しましょう。

Signals の設定 - データとフィルターの Signals を定義します

import { Component } from '@angular/core';
import { signal, computed, effect } from '@angular/core';
import { IgxGridComponent } from 'igniteui-angular';
 
@Component({
  selector: 'app-data-grid',
  template: `
    <igx-grid [data]="filteredData()">
      <!-- Define your grid columns here -->
    </igx-grid>
  `
})
export class DataGridComponent {
  data = signal([]);  // Signal to store our data
  filter = signal('');  // Signal for filtering the data
 
  // Computed signal to apply the filter to the data
  filteredData = computed(() =>
    this.data().filter(item => item.name.includes(this.filter()))
  );
 
  constructor() {
    // Effect to log changes for debugging
    effect(() => {
      console.log('Data or filter changed:', this.filteredData());
    });
  }
 
  // Method to fetch and update data
  fetchData(newData) {
    this.data.set(newData);
  }
}

データの更新: 新しいデータを取得し、シグナルを更新します

fetchData(newData) {
      this.data.set(newData);
    }

スムーズなアップデートを体験

グリッドは、Angular Signalsの強力なリアクティブ性とIgnite UIの効率的なレンダリングによって、データが変更されるとリアルタイムで更新されます。しかし、ここには別の例があります - Angular Signalsを使用しない場合の例です。

import { Component } from '@angular/core';
 
@Component({
  selector: 'app-data-grid',
  template: `
    <input [(ngModel)]="filter" (ngModelChange)="applyFilter()" placeholder="Filter" />
    <igx-grid [data]="filteredData">
      <!-- Define your grid columns here -->
    </igx-grid>
  `
})
export class DataGridComponent {
  data = [];  // Data array
  filteredData = [];  // Filtered data array
  filter = '';  // Filter string
 
  applyFilter() {
    this.filteredData = this.data.filter(item => item.name.includes(this.filter));
  }
 
  fetchData(newData) {
    this.data = newData;
    this.applyFilter();
  }
}
With:
import { Component } from '@angular/core';
import { signal, computed, effect } from '@angular/core';
 
@Component({
  selector: 'app-data-grid',
  template: `
    <input [value]="filter()" (input)="filter.set($event.target.value)" placeholder="Filter" />
    <igx-grid [data]="filteredData()">
      <!-- Define your grid columns here -->
    </igx-grid>
  `
})
export class DataGridComponent {
  data = signal([]);  // Signal to store data
  filter = signal('');  // Signal for filter
 
  // Computed signal to filter data
  filteredData = computed(() =>
    this.data().filter(item => item.name.includes(this.filter()))
  );
 
  constructor() {
    // Effect to log changes for debugging
    effect(() => {
      console.log('Data or filter changed:', this.filteredData());
    });
  }
 
   fetchData(newData) {
    this.data.set(newData);
  }
}

結論として...

ここでは、Angular Signalsを使用する理由を簡単に説明します。Angular Signalsを使用しない場合、状態とその影響を手動で更新および管理する必要があります。これには、状態を更新し、変更をトリガーする関数を記述することが含まれるため、コードがより複雑になり、エラーが発生しやすくなります。Angular Signalsを使用すると、状態管理がより宣言的で効率的になり、エラーが発生しにくくなり、パフォーマンスと保守性の両方が向上します。

画像説明

この記事の原文は以下よりご確認いただけます。 [Katie Mikova(https://www.infragistics.com/community/blogs/b/infragistics/posts/angular-signals?gasource=login.microsoftonline.com&gamedium=referral&gacampaign=(not+set)&gaterm=&gagclid=) (ケイティ・ミコヴァ) / 2024年7月17日(水)