ホームページ >ウェブフロントエンド >jsチュートリアル >Angular resource() および rxResource() API: 知っておくべきこと

Angular resource() および rxResource() API: 知っておくべきこと

DDD
DDDオリジナル
2025-01-04 06:52:43487ブラウズ

Angular resource() and rxResource() APIs: what you need to know

ほんの数週間前の Angular v19 のリリースは、Input、モデル出力、およびシグナルクエリ API が正式に安定版に昇格しました。

しかし、それだけではありません!このメジャー バージョンでは、信号革命をさらに前進させるために設計された強力な新しいツール、新しい

Resource API も導入されています。

名前が示すように、この新しい

リソース API は、シグナルの能力を最大限に活用することで 非同期リソース のロードを簡素化するように設計されています。

重要: の執筆時点では、新しい リソース API はまだ実験段階です。つまり、安定する前に変更される可能性があるため、自己責任で使用してください。 ?

その仕組みと、非同期リソースの処理がどのように簡素化されるのかを詳しく見てみましょう!


リソース API

ほとんどのシグナル API は同期ですが、実際のアプリケーションでは、サーバーからのデータの取得やリアルタイムでのユーザー インタラクションの管理など、非同期リソースを処理することが不可欠です。

ここで、新しい

Resource API が登場します。

リソースを使用すると、シグナル経由で非同期リソースを簡単に消費できるため、データのフェッチの管理、読み込み状態の処理、関連するシグナル パラメーターが変更されるたびに新しいフェッチのトリガーを簡単に行うことができます。

resource( ) 関数

リソースを作成する簡単な方法は、resource() 関数を使用することです。

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

const RESOURCE_URL = 'https://jsonplaceholder.typicode.com/todos/';

private id = signal(1);

private myResource = resource({
    request: () => ({ id: this.id() }),
    loader: ({ request }) => fetch(RESOURCE_URL + request.id),
});
この関数は、

ResourceOptions 構成オブジェクトを入力として受け入れ、次のプロパティを指定できます。

  • request: 非同期リソースへのリクエストを実行するために使用されるパラメーターを決定する リアクティブ関数;
  • loader: オプションで指定された request パラメーターに基づいて、リソースの値の Promise を返す読み込み関数。これは、ResourceOptions; の唯一の必須 プロパティです。
  • equal: loader の戻り値を比較するために使用される等価関数;
  • injector: Resource インスタンスによって使用される Injector をオーバーライドして、親コンポーネントまたはサービスが破棄されるときにそれ自体を破棄します。
これらの構成のおかげで、常に効率的に使用され、最新の状態に保たれる

非同期依存関係 を簡単に定義できます。

リソースのライフサイクル

リソースが作成されると、loader関数が実行され、その結果として生じる非同期リクエストが開始されます。

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

const RESOURCE_URL = 'https://jsonplaceholder.typicode.com/todos/';

private id = signal(1);

private myResource = resource({
    request: () => ({ id: this.id() }),
    loader: ({ request }) => fetch(RESOURCE_URL + request.id),
});

request 関数が依存するシグナルが変更されるたびに、request 関数が再度実行され、新しいパラメーターが返された場合は、loader 関数がトリガーされます。更新されたリソースの値を取得するには:

import { resource, signal } from "@angular/core";

const RESOURCE_URL = "https://jsonplaceholder.typicode.com/todos/";

const id = signal(1);
const myResource = resource({
  request: () => ({ id: id() }),
  loader: ({ request }) => fetch(RESOURCE_URL + request.id)
});
console.log(myResource.status()); // Prints: 2 (which means "Loading")

request 関数が指定されていない場合、reload を使用して Resource が再ロードされない限り、loader 関数は 1 回だけ実行されます。メソッド (詳細は後述)。

最後に、親コンポーネントまたはサービスが破棄されると、特定のインジェクターが提供されていない限り、リソース も破棄されます。

そのような場合、リソースはアクティブなままとなり、提供されたインジェクター自体が破棄された場合にのみ破棄されます。

abortSignal によるリクエストの中止

データのフェッチを最適化するために、前の値がまだロードされている間に request() の計算が変更された場合、リソース は未処理のリクエストを中止できます。

これを管理するために、loader() 関数は、fetch などの進行中のリクエストに渡すことができる abortSignal を提供します。リクエストは abortSignal をリッスンし、トリガーされた場合は操作をキャンセルします。これにより効率的なリソース管理が確保され、不要なネットワーク リクエストが防止されます。

import { resource, signal } from "@angular/core";

const RESOURCE_URL = "https://jsonplaceholder.typicode.com/todos/";

const id = signal(1);
const myResource = resource({
  request: () => ({ id: id() }),
  loader: ({ request }) => fetch(RESOURCE_URL + request.id)
});

console.log(myResource.status()); // Prints: 2 (which means "Loading")

// After the fetch resolves

console.log(myResource.status()); // Prints: 4 (which means "Resolved")
console.log(myResource.value()); // Prints: { "id": 1 , ... }

id.set(2); // Triggers a request, causing the loader function to run again
console.log(myResource.status()); // Prints: 2 (which means "Loading")

// After the fetch resolves

console.log(myResource.status()); // Prints: 4 (which means "Resolved")
console.log(myResource.value()); // Prints: { "id": 2 , ... }

これに基づき、通常は問題を引き起こすことなく安全にキャンセルできるため、GET リクエストには主に Resource API を使用することをお勧めします。

POST または UPDATE リクエストの場合、キャンセルすると不完全なデータ送信や更新などの予期しない副作用が発生する可能性があります。ただし、これらのタイプのリクエストに同様の機能が必要な場合は、effect() メソッドを使用して操作を安全に管理できます。


リソースの消費方法

リソース API は、コンポーネントまたはサービス内で直接簡単に使用できる、その状態の信号プロパティをいくつか提供します。

  • value: Resource の現在の値が含まれます。値が使用できない場合は 未定義 が含まれます。 WritableSignal として、手動で更新できます。
  • status: リソースの現在のステータスが含まれており、リソースが何を行っているか、およびそのから何が期待できるかを示します。
  • error: エラー状態の場合、Resource ロード中に発生した最新のエラーが含まれます。
  • isLoading: リソース が新しい値をロードしているか、既存の値を再ロードしているかを示します。

コンポーネント内で リソース を消費する方法の例を次に示します。

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

const RESOURCE_URL = 'https://jsonplaceholder.typicode.com/todos/';

private id = signal(1);

private myResource = resource({
    request: () => ({ id: this.id() }),
    loader: ({ request }) => fetch(RESOURCE_URL + request.id),
});

この例では、Resource は、id 信号の値に基づいて API からデータをフェッチするために使用されます。

id

信号の値は、ボタンをクリックすることで増加できます。 ユーザーがボタンをクリックするたびに、id シグナル値が変化し、

loader

関数がトリガーされてリモート API から新しい項目を取得します。

Resource
API によって公開されるシグナル プロパティのおかげで、UI はフェッチされたデータで自動的に更新されます。

リソースのステータスを確認する 前述したように、

status

シグナルは、任意の瞬間におけるリソースの現在の状態に関する情報を提供します。 status 信号の可能な値は、

ResourceStatus
    列挙型によって定義されます。これらのステータスとそれに対応する値の概要は次のとおりです:
  • Idle = 0: リソース には有効なリクエストがないため、ロードは実行されません。 value()
  • 未定義
  • ; Error = 1: 読み込みがエラーで失敗しました。 value()
  • 未定義
  • ; Loading = 2: リソースは現在、リクエストの変更の結果として新しい値をロードしています。 value()
  • 未定義
  • ; Reloading = 3: リソースは現在、同じリクエストの新しい値を再ロードしています。
  • value()
  • は、リロード操作が完了するまで、以前に取得した値を返し続けます。 解決 = 4: 読み込みが完了しました。
  • value()
  • には、ローダーのデータ取得プロセスから返された値が含まれます。 Local = 5: 値は set() または update() を介してローカルに設定されました。
  • value()
には、手動で割り当てられた値が含まれます。

これらのステータスは、

リソースの進行状況を追跡し、アプリケーションでの非同期操作の処理を容易にするのに役立ちます。

hasValue( ) 関数

これらのステータスの複雑さを考慮して、リソース API は、現在のステータスに基づいてブール値を返す hasValue() メソッドを提供します。

これにより、リソースのステータスに関する正確な情報が保証され、特定の状態では未定義となる可能性がある値に依存せずに、非同期操作を処理するためのより信頼性の高い方法が提供されます。

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

const RESOURCE_URL = 'https://jsonplaceholder.typicode.com/todos/';

private id = signal(1);

private myResource = resource({
    request: () => ({ id: this.id() }),
    loader: ({ request }) => fetch(RESOURCE_URL + request.id),
});

このメソッドはリアクティブであるため、シグナル のように消費および追跡できます。

isLoading()関数

Resource API は、リソースが現在 Loading 状態か Reloading 状態であるかを返す isLoading シグナルも提供します。

import { resource, signal } from "@angular/core";

const RESOURCE_URL = "https://jsonplaceholder.typicode.com/todos/";

const id = signal(1);
const myResource = resource({
  request: () => ({ id: id() }),
  loader: ({ request }) => fetch(RESOURCE_URL + request.id)
});
console.log(myResource.status()); // Prints: 2 (which means "Loading")

isLoading は計算された信号であるため、事後的に追跡でき、信号 API を使用して読み込み状態をリアルタイムで監視できます。


WritableSignal としてのリソース値

Resource によって提供される値シグナルは WritableSignal です。これにより、set()update( ) 関数:

import { resource, signal } from "@angular/core";

const RESOURCE_URL = "https://jsonplaceholder.typicode.com/todos/";

const id = signal(1);
const myResource = resource({
  request: () => ({ id: id() }),
  loader: ({ request }) => fetch(RESOURCE_URL + request.id)
});

console.log(myResource.status()); // Prints: 2 (which means "Loading")

// After the fetch resolves

console.log(myResource.status()); // Prints: 4 (which means "Resolved")
console.log(myResource.value()); // Prints: { "id": 1 , ... }

id.set(2); // Triggers a request, causing the loader function to run again
console.log(myResource.status()); // Prints: 2 (which means "Loading")

// After the fetch resolves

console.log(myResource.status()); // Prints: 4 (which means "Resolved")
console.log(myResource.value()); // Prints: { "id": 2 , ... }

注: ご覧のとおり、シグナルの を手動で更新すると、ステータスも 5 に設定されます。これは、「ローカル」を意味します"、値がローカルに設定されたことを示します。

手動で設定した値は、新しい値が設定されるか、新しいリクエストが実行されるまで保持され、新しい値でオーバーライドされます。

import { resource, signal } from "@angular/core";

const RESOURCE_URL = "https://jsonplaceholder.typicode.com/todos/";

const id = signal(1);
const myResource = resource({
  request: () => ({ id: id() }),
  loader: ({ request, abortSignal }) =>
    fetch(RESOURCE_URL + request.id, { signal: abortSignal })
});

console.log(myResource.status()); // Prints: 2 (which means "Loading")

// Triggers a new request, causing the previous fetch to be aborted
// Then the loader function to run again generating a new fetch request
id.set(2);

console.log(myResource.status()); // Prints: 2 (which means "Loading")

注: リソース API シグナルは、新しい LinkedSignal API と同じパターンを使用しますが、それはボンネットの下にあります。 ?

便利なラッパーメソッド

value シグナルの使用を簡素化するために、Resource API は、setupdate、および asReadonly メソッド。

asReadonly メソッドは、value 信号の読み取り専用インスタンスを返し、読み取りのみのアクセスを許可し、誤った変更を防ぐため、特に便利です。

このアプローチを使用すると、

の読み取り専用インスタンスをエクスポートすることで、リソース値の変更を管理および追跡するサービスを作成できます:

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

const BASE_URL = 'https://jsonplaceholder.typicode.com/todos/';

@Component({
  selector: 'my-component',
  template: `
    @if (myResource.value()) {
      {{ myResource.value().title }}
    }

    <button (click)="fetchNext()">Fetch next item</button>
  `
})
export class MyComponent {
  private id = signal(1);

  protected myResource = resource({
    request: () => ({ id: this.id() }),
    loader: ({ request }) =>
      fetch(BASE_URL + request.id).then((response) => response.json()),
  });

  protected fetchNext(): void {
    this.id.update((id) => id + 1);
  }
}
これにより、消費者による値の変更が防止され、意図しない変更のリスクが軽減され、複雑なデータ管理の一貫性が向上します。


リソースをリロードまたは破棄する

非同期リソースを操作する場合、データの更新や リソース の破棄が必要になるシナリオに直面する可能性があります。

これらのシナリオを処理するために、リソース API は、これらのアクションを管理するための効率的なソリューションを提供する 2 つの専用メソッドを提供します。

リロード()関数

reload() メソッドは、Resource に非同期リクエストを再実行するように指示し、最新のデータを確実にフェッチします。

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

const RESOURCE_URL = 'https://jsonplaceholder.typicode.com/todos/';

private id = signal(1);

private myResource = resource({
    request: () => ({ id: this.id() }),
    loader: ({ request }) => fetch(RESOURCE_URL + request.id),
});

リロードが正常に開始された場合、reload() メソッドは true を返します。

ステータスがすでに Loading または Reloading である場合など、リロードが不要であるか、ステータスが である場合など、サポートされていないため、リロードを実行できない場合アイドル、メソッドは false を返します。

destroy( ) 関数

destroy() メソッドは、Resource を手動で破棄し、リクエストの変更を追跡するために使用されるすべての effect() を破棄し、保留中のリクエストをキャンセルして、ステータスをアイドルにリセットしながら、値を未定義:

import { resource, signal } from "@angular/core";

const RESOURCE_URL = "https://jsonplaceholder.typicode.com/todos/";

const id = signal(1);
const myResource = resource({
  request: () => ({ id: id() }),
  loader: ({ request }) => fetch(RESOURCE_URL + request.id)
});
console.log(myResource.status()); // Prints: 2 (which means "Loading")

リソースが破棄されると、リクエストの変更や reload() 操作に応答しなくなります。

注: この時点では、value 信号は書き込み可能なままですが、リソース は本来の目的を失い、その機能を果たさなくなり、役に立たなくなります。 。 ?


rxResource( ) 関数

これまでに紹介したほぼすべてのシグナルベースの API と同様、Resource API も、RxJS とのシームレスな統合のための相互運用性ユーティリティを提供します。

resource() メソッドを使用して Promise ベースの Resource を作成する代わりに、rxResource() メソッドを使用して を使用できます。観測対象:

import { resource, signal } from "@angular/core";

const RESOURCE_URL = "https://jsonplaceholder.typicode.com/todos/";

const id = signal(1);
const myResource = resource({
  request: () => ({ id: id() }),
  loader: ({ request }) => fetch(RESOURCE_URL + request.id)
});

console.log(myResource.status()); // Prints: 2 (which means "Loading")

// After the fetch resolves

console.log(myResource.status()); // Prints: 4 (which means "Resolved")
console.log(myResource.value()); // Prints: { "id": 1 , ... }

id.set(2); // Triggers a request, causing the loader function to run again
console.log(myResource.status()); // Prints: 2 (which means "Loading")

// After the fetch resolves

console.log(myResource.status()); // Prints: 4 (which means "Resolved")
console.log(myResource.value()); // Prints: { "id": 2 , ... }

注: rxResource() メソッドは、実際には rxjs-interop パッケージによって公開されています。

loader() 関数によって生成される Observable は、最初に出力された値のみを考慮し、後続の出力は無視します。


ここまで読んでいただきありがとうございます?

この素晴らしい 2024 年を通して私をフォローしていただきありがとうございました。 ??

今年は課題に満ちた年でしたが、とてもやりがいのある年でもありました。私には 2025 年に向けた大きな計画があり、それに取り組み始めるのが待ちきれません。 ?

フィードバックをお待ちしておりますので、コメントいいね、または フォローをお願いいたします。 ?

本当に気に入った場合は、コミュニティ、技術者仲間、その他好きな人に共有してください。 LinkedIn で私をフォローしてください。 ??

以上がAngular resource() および rxResource() API: 知っておくべきことの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。