ハイサイ!オースティンやいびーん。んな、がんじゅー やいびーみ?
概要
Angular 16のリリースに含まれる予定の新原始型Signal
を使っていくつかの具体的な使用例を紹介します!
Signal
とは?
Angularのフレームワークが変更をパフォーマンスよく検知するための新しいReactive Primitiveです。
SolidJSのsignalと概念が一緒で、非常に単純です。Signalには以下の二つの特徴があります。
- 値を保持している
- 値が変わった時に信号を出す能力を持っている
上記の二つの特徴をAngularで使うと、同期的な処理を簡単にテンプレートに反映できます。
SignalとAngularの変更について詳しくは以下の記事をご覧ください。
試験的にSignal APIを使う方法
Signalを今でも使ってみたい!という方、実はもうすでにPOCとしてAngularチームが実装して出してくれています!
使うためには@angular/cli@16.0.0
を使う必要があります。
まだ試験的にバージョンがよく変わるので、npmで今現在の最新のバージョンを確認してください。
上記のnpmページから最新のバージョンを取得したら以下のコマンドに代入して実行すればAngular 16のプロジェクトを作ることができます。
npx -p @angular/cli@16.0.0-next.6 ng new signals-play
そうするとng serve
を実行してAngularのアプリが起動するか確認してください。
Signalを部品とテンプレートで使う
app.component.ts
でsignal
をインポートしてみましょう。
import { Component, signal } from '@angular/core';
補足説明が書いてありますが、@developerPreview
になっています。
以下のように初期値を代入すると型を推測してくれます。
import { Component, signal } from '@angular/core';
@Component({
...
})
export class AppComponent {
clickCount = signal(0);
addClick() {
this.clickCount.update((clicks) => clicks + 1);
// OR
this.clickCount.set(this.clickCount() + 1);
}
}
テンプレートで以下のように現在の値を表示できます。テンプレートではclickCount
を関数として呼び、現在の値を取得します。
<h1>Count: </h1>
<p>{{ this.clickCount() }}</p>
<button (click)="this.addClick()" type="button">Add 2</button>
「テンプレートで関数を呼ぶのは危険」と経験上ご存知の方もいらっしゃるかと思いますが、Signalは副作用を起こさないので心配無用です。
以下のような結果になります。
非常に簡単です。
computedの使い方
Signalは上記の説明の通り、値を持ってそれが変わった時にその変化を知らせるという二つの役割しかないのです。
ただ、同期処理の多くは、値と値を使って何かを計算することがほとんどです。
signal同士を使って計算する時は、computed
という関数を使います!
以下、ページボタンの例で紹介します。
import { Component, signal, computed } from '@angular/core';
@Component({
...
})
export class AppComponent {
private itemCount = signal(124);
private itemsPerPage = signal(10);
currentPage = signal(0);
pageCount = computed(() => Math.ceil(this.itemCount() / this.itemsPerPage()));
canGoForward = computed(() => this.currentPage() < this.pageCount());
canGoBack = computed(() => this.currentPage() !== 0);
goForward() {
if (!this.canGoForward()) return;
this.currentPage.update((pageNo) => pageNo + 1);
}
goBack() {
if (!this.canGoBack()) return;
this.currentPage.update((pageNo) => pageNo - 1);
}
}
テンプレートでは以下のようにボタンの属性にも上記のロジックを適応させます。
<h1>Current Page</h1>
<p>{{ this.currentPage() }}</p>
<nav>
<button (click)="this.goBack()" type="button" [disabled]="!this.canGoBack()">Back</button>
<button (click)="this.goForward()" type="button" [disabled]="!this.canGoForward()">Next</button>
</nav>
結果
とても簡単で素晴らしい!
まとめ
徐々にAngularのSignalが具体性を高めてきていますが、ワクワクが絶えません。
やっぱり上記のような同期処理を各ロジックが非常に簡単になりそうなので助かります。
また、Vueにも似たような文法なので、筆者は受け入れやすい感じです。
みんなもぜひ試してみてください!