首頁 > web前端 > js教程 > Angular resource() 和 rxResource() API:您需要了解的內容

Angular resource() 和 rxResource() API:您需要了解的內容

DDD
發布: 2025-01-04 06:52:43
原創
474 人瀏覽過

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

幾週前發布的Angular v19 標誌著框架內訊號革命的一個重要里程碑,輸入模型輸出訊號查詢 API現已正式升級為穩定版。

但這還不是全部!這個主要版本也引進了旨在進一步推進訊號革命的強大新工具:新的資源API

顧名思義,這個新的資源 API 旨在透過充分利用訊號的力量來簡化載入非同步資源

重要提示:在撰寫本文時,新的資源 API 仍處於實驗階段。這意味著它在變得穩定之前可能會發生變化,因此使用它需要您自擔風險。 ?

讓我們深入了解它的工作原理以及它如何簡化非同步資源的處理!


資源 API

大多數訊號 API 都是同步的,但在實際應用中,處理非同步資源至關重要,例如從伺服器取得資料或即時管理使用者互動。

這就是新的資源 API 發揮作用的地方。

使用資源,您可以輕鬆地透過訊號消耗非同步資源,從而輕鬆管理資料擷取、處理載入狀態,並在相關訊號參數變更時觸發新的擷取。

資源( ) 函數

建立資源更簡單的方法是使用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 配置物件作為輸入,允許您指定以下屬性:

  • 請求:一個反應函數,用於確定用於執行對非同步資源的請求的參數;
  • loader:一個載入函數,傳回資源值的 Promise,可以選擇基於提供的 request 參數。這是 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 函數,則loader 函數將只運行一次,除非使用reload重新載入Resource方法(更多下文)。

最後,一旦父元件或服務被銷毀,資源也會被銷毀,除非提供了特定的注入器。

在這種情況下,資源將保持活動狀態,並且僅當提供的注入器本身被銷毀時才會被銷毀。

使用 abortSignal 中止請求

為了優化資料獲取,如果 request() 計算發生變化而先前的值仍在加載,資源 可以中止未完成的請求。

為了管理此問題,loader() 函數提供了 abortSignal,您可以將其傳遞給正在進行的請求,例如 fetch。此請求監聽 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,因為它們通常可以安全地取消而不會引起問題。

對於 POSTUPDATE 請求,取消可能會導致意想不到的副作用,例如不完整的資料提交或更新。但是,如果您需要針對這些類型的請求提供類似的功能,則可以使用 effect() 方法來安全地管理操作。


如何使用資源

資源 API 為其狀態提供了多個訊號屬性,您可以直接在元件或服務中輕鬆使用它們:

  • :包含資源的目前值,如果沒有可用值,則包含未定義。作為WritableSignal,可以手動更新;
  • 狀態:包含資源的當前狀態,指示資源正在做什麼以及可以從其中得到什麼;
  • 錯誤:如果處於錯誤狀態,則包含資源載入期間引發的最新錯誤;
  • 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 訊號​​值都會發生變化,從而觸發 loader 函數從遠端 API 取得新項目。

由於 Resource API 公開的訊號屬性,UI 會自動使用所取得的資料進行更新。


檢查資源的狀態

如前所述,狀態訊號提供有關資源在任何給定時刻的當前狀態的資訊。

status 訊號​​的可能值由 ResourceStatus 列舉定義。以下是這些狀態及其對應值的摘要:

  • 空閒 = 0資源沒有有效要求,不會執行任何載入。 value()未定義;
  • Error = 1:載入失敗並出現錯誤。 value()未定義;
  • 正在載入 = 2:由於請求發生更改,資源目前正在載入新值。 value()未定義;
  • 正在重新載入 = 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 也提供了 isLoading 訊號​​,該訊號會傳回資源目前是否處於 LoadingReloading 狀態:

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")
登入後複製

注意: Resource APIvalue 訊號​​使用與新的LinkedSignal API 相同的模式,但不使用它在引擎蓋下。 ?

便利包裝方法

為了簡化value 訊號​​的使用,Resource API 為setupdateupdateasReadonly 方法。

asReadonly 方法特別有用,因為它會傳回 value 訊號​​的唯讀實例,僅允許讀取存取並防止任何意外修改。

您可以使用此方法透過匯出 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 提供了兩種專用方法,為管理這些操作提供有效的解決方案。

重新載入()函數

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

如果無法執行重新加載,無論是因為沒有必要,例如當狀態已正在加載正在重新加載,或不支持,例如當狀態為時空閒,該方法回傳false.

銷毀()函數

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訊號仍然可寫,但Resource將失去其預期目的,不再發揮其功能,變得無用。 ?


rxResource( ) 函數

與迄今為止引入的幾乎所有基於訊號的 API 一樣,資源 API 還提供了一個互通性實用程序,用於與 RxJS 無縫整合。

您可以使用rxResource() 方法來建立基於Promise 的Resource,而不是使用resource() 方法來使用可觀察

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中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板