Angular の反応性の次の改善

Mary-Kate Olsen
リリース: 2024-11-17 22:19:01
オリジナル
186 人が閲覧しました

The next improvement in Angular reactivity

導入

Angular の最新バージョン以降、新しい基本的な反応性システムがフレームワーク内で開発されました: シグナル!

今日、後から考えると、特定のユースケースがカバーされていなかったことに気づきました。当然、非常に積極的な Angular チームが、これらのユースケースをカバーするためのヘルパーを提供してくれるでしょう。

これらの使用例は何ですか?どのようなソリューションが導入され、どのように使用されるのでしょうか?

ある信号を別の信号に対してリセットするプロセス

この問題を説明することから始めましょう。

一定量の果物が入ったバスケットがあると想像してみましょう。
数量は果物を入力するコンポーネントによって管理されます。

@Component({
  template: `<button type="button" (click)="updateQuantity()"> 
    {{quantity()}}
    </button>`
})
export class QuantityComponent() {
  fruit = input.required<string>();
  count = signal(1);

  updateQuantity(): void {
    this.count.update(prevCount => prevCount++);
  }
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

入力価格フルーツが変化した場合、ここで変数をリセットする必要があります。

簡単な解決策はエフェクトを使用することです

@Component({
  template: `<button type="button" (click)="updateQuantity()"> 
    {{quantity()}}
    </button>`
})
export class QuantityComponent() {
  fruit = input.required<string>();
  quantity = signal(1);

  countEffect(() => {
    this.fruit();
    this.quantity.set(1);
  }, { allowSignalWrites: true })

  updateQuantity(): void {
    this.quantity.update(prevCount => prevCount++);
  }
}
ログイン後にコピー
ログイン後にコピー

上記のコードは悪い習慣です。なぜこれが大きな疑問なのでしょうか?

シグナル量を設定するには、signalWrites オプションを true に設定する必要があります。これは、与えられた問題の誤解が原因です。
私たちの場合、実体化では非同期化されている 2 つの変数を同期したいと考えています

カウンターは、最初のソースであるフルーツから独立していません。実際には、ここにはコンポーネント状態があり、その最初のソースはフルーツであり、残りはフルーツの派生です。

問題を次のように具体化します

@Component({
  template: `<button type="button" (click)="updateQuantity()"> 
    {{fruitState().quantity()}}
    </button>`
})
export class QuantityComponent() {
  fruit = input.required<string>();

  fruitState = computed(() => ({
    source: fruit(),
    quantity: signal(1),
  }));

  updateQuantity(): void {
    this.fruitState().quantity.update(prevCount => prevCount++);
  }
}
ログイン後にコピー
ログイン後にコピー

この物質化は、果物とその量とを強く結びつけます。
したがって、フルーツが変化するとすぐに、計算変数 FruitState が自動的に再計算されます。この再計算では、数量プロパティを持つオブジェクトが返されます。これは、1 に初期化された信号です。

シグナルを返すことで、クリック時に変数をインクリメントし、フルーツが変化したときに単純にリセットできます。

設定は比較的簡単なパターンですが、もっと簡素化できないでしょうか?

LinkedSignal 機能が役に立ちます。

Angular 19 の登場により、派生信号を計算するための新しい関数が追加されました。

これまでは計算関数がありましたが、この関数は WrittableSignal ではなく Signal を返します。これは量変数の以前の使用例では実用的でした。

ここで LinkedSignal が登場します。LinkedSignal を使用すると、その名前が示すように、2 つの信号を強力にリンクできます。

前のケースに戻ると、この関数を使用するとコードを次のように簡略化できます。

@Component({
  template: `<button type="button" (click)="updateQuantity()"> 
    {{quantity()}}
    </button>`
})
export class QuantityComponent() {
  fruit = input.required<string>();
  quantity = linkedSignal({ source: fruit, computation: () => 1 });

  updateQuantity(): void {
    this.quantity.update(prevCount => prevCount++);
  }
}
ログイン後にコピー
ログイン後にコピー

linkedSignal 関数は次のように定義されます:

linkedSignal(computation: () => D, options?: { equal?: ValueEqualityFn<NoInfer<D>>; }): WritableSignal<D>;

linkedSignal(options: { source: () => S; computation: (source: NoInfer<S>, previous?: { source: NoInfer<S>; value: NoInfer<D>; }) => D; equal?: ValueEqualityFn<NoInfer<D>>; }): WritableSignal<D>;
ログイン後にコピー
ログイン後にコピー

最初の定義 (「省略された」定義) では、linkedSignal 関数は計算関数をパラメーターおよび構成オブジェクトとして受け取ります。

@Component({
  template: `<button type="button" (click)="updateQuantity()"> 
    {{quantity()}}
    </button>`
})
export class QuantityComponent() {
  fruit = input.required<string>();
  count = signal(1);

  updateQuantity(): void {
    this.count.update(prevCount => prevCount++);
  }
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

この前の例では、計算関数は信号の量に依存するため、量が変化すると計算関数が再評価されます。

2 番目の定義では、linkedFunction メソッドは 3 つのプロパティを持つパラメーターとしてオブジェクトを受け取ります

  • ソース: 計算関数の再評価の基礎となる信号
  • 計算関数
  • パラメータオブジェクト

「省略された」計算関数とは対照的に、ここでの計算関数はソースの値と「前例」をパラメーターとして受け取ります。

@Component({
  template: `<button type="button" (click)="updateQuantity()"> 
    {{quantity()}}
    </button>`
})
export class QuantityComponent() {
  fruit = input.required<string>();
  quantity = signal(1);

  countEffect(() => {
    this.fruit();
    this.quantity.set(1);
  }, { allowSignalWrites: true })

  updateQuantity(): void {
    this.quantity.update(prevCount => prevCount++);
  }
}
ログイン後にコピー
ログイン後にコピー

新しいリソース API

Angular 19 では、単純なデータのフェッチと、クエリ ステータス (保留中など)、データ、エラーの取得のための新しい API が導入されます。

フレームワークに少し慣れている人にとって、この新しい API は useRessource フックと少し似た働きをします。

例を見てみましょう:

@Component({
  template: `<button type="button" (click)="updateQuantity()"> 
    {{fruitState().quantity()}}
    </button>`
})
export class QuantityComponent() {
  fruit = input.required<string>();

  fruitState = computed(() => ({
    source: fruit(),
    quantity: signal(1),
  }));

  updateQuantity(): void {
    this.fruitState().quantity.update(prevCount => prevCount++);
  }
}
ログイン後にコピー
ログイン後にコピー

このコード スニペットについては、知っておくべきことがいくつかあります

このスニペット コードには注意すべき点がいくつかあります:

  • デフォルトでは、ローダーはパラメーターとして Promise を受け取ります
  • fruitRessource タイプは WrittableRessource であり、必要に応じてローカルでデータを変更できるようになります
  • フルーツの詳細のリクエストは、リソース fuitResource の作成時にサーバーに直接送信されます
  • this.fruitId() はローダーで追跡されないため、fruitId が変更されても新しいリクエストは送信されません
  • WrittableRessource にはデータを更新するためのメソッド refresh があります

次の効果はそれらの値を出力します

@Component({
  template: `<button type="button" (click)="updateQuantity()"> 
    {{quantity()}}
    </button>`
})
export class QuantityComponent() {
  fruit = input.required<string>();
  quantity = linkedSignal({ source: fruit, computation: () => 1 });

  updateQuantity(): void {
    this.quantity.update(prevCount => prevCount++);
  }
}
ログイン後にコピー
ログイン後にコピー

上で説明したように、デフォルトでは、fruitId シグナルは追跡されません。

では、このシグナルの値が変化するたびに http リクエストを再開するにはどうすればよいでしょうか。また、fruitId シグナルの値が変化し、前のリクエストへの応答が変化しなかった場合に、前のリクエストをキャンセルするにはどうすればよいでしょうか。到着しますか?

リソース関数は、request と呼ばれる別のプロパティを受け取ります。

このプロパティは、信号に依存する関数を値として受け取り、その値を返します。

linkedSignal(computation: () => D, options?: { equal?: ValueEqualityFn<NoInfer<D>>; }): WritableSignal<D>;

linkedSignal(options: { source: () => S; computation: (source: NoInfer<S>, previous?: { source: NoInfer<S>; value: NoInfer<D>; }) => D; equal?: ValueEqualityFn<NoInfer<D>>; }): WritableSignal<D>;
ログイン後にコピー
ログイン後にコピー

上記のコードに示すように、ローダー関数は 2 つのパラメーターを取ります

  • リクエスト値: ここでは、fruitId シグナルの値
  • http リクエストをキャンセルするために使用される abortController オブジェクトの signal プロパティの値。

果物の詳細を取得する httpRequest 中に FruitId シグナルの値が変更された場合、リクエストはキャンセルされて新しいリクエストが開始されます。

最後に、Angular は、この新しい API を RxJ と組み合わせて、Rx オペレーターのパワーを活用できるようにする可能性も考えました。

相互互換性は、resource 関数とまったく同じ方法で定義される rxResource 関数を使用して実現されます。
唯一の違いは、observable
を返すローダー プロパティの戻り値の型です。

@Component({
  template: `<button type="button" (click)="updateQuantity()"> 
    {{quantity()}}
    </button>`
})
export class QuantityComponent() {
  fruit = input.required<string>();
  count = signal(1);

  updateQuantity(): void {
    this.count.update(prevCount => prevCount++);
  }
}
ログイン後にコピー
ログイン後にコピー
ログイン後にコピー

ここでは、abortSignal を使用する必要はありません。これは、シグナル FruitId の変更の値が関数 rxResource で暗黙的に変更され、動作が switchMap オペレーターと同じになる場合に、前のリクエストをキャンセルすることを意味します。

以上がAngular の反応性の次の改善の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート