# Angular19 Signals + HTTP = httpResource ==此為翻譯文章,純分享== Angular 19.2 引入了一個實驗性的新 API,稱為 httpResource。 先從基礎開始談起。隨著 Angular 框架逐步導入 Signals,許多人也開始關注一個問題:既然 HttpClient 是回傳 Observable,那該如何與 Signals 搭配使用? 簡單的答案是:可以使用 toSignal 函式來轉換。 ```typescript= signal = toSignal(this.http.get("http://mydata.com")); ``` 雖然上述方法可行,但它無法清楚知道以下狀況: * 資料是否已載入?是否還在載入中? * 請求過程中是否發生錯誤? 而 resource API 就解決了這些問題,因為它會回傳一組 Signals 和方法,能夠幫助我們掌握所有這些狀態 ![image](https://hackmd.io/_uploads/HyCU8a9Zeg.png) 可以檢查 resource.hasValue() 或 resource.isLoading() 來取得狀態. ## 如何建立 httpResource 建立一個用於 HTTP 請求的 resource 非常簡單: ```typescript= resource = httpResource('https://dummyjson.com/users'); ``` 當然,也可以透過 TypeScript 加上類型資訊,來指定從伺服器回傳的資料結構: ```typescript= resource = httpResource<UserList>('https://dummyjson.com/users'); ``` 現在,如果我們想要在畫面上顯示從伺服器取得的資料,只需要這樣寫: ```typescript= @for(user of resource.value()?.users; track user.id) { <div class="user"> {{user.firstName}} {{user.lastName}} - {{user.age}} 歲 </div> } ``` 而如果想在資料載入期間顯示一個載入動畫(例如 spinner),只需要加上以下程式碼: ```typescript= @if (resource.isLoading()) { <img src="https://i.gifer.com/ZZ5H.webp" width="50px" /> } ``` 範例連結:http://stackblitz.com/edit/ng-http-resource-simple?file=src%2Fmain.ts ## HTTP 資源以後還能再被觸發嗎? 答案是:可以,而且最棒的是,這一切都是基於 Signal 的設計! 舉個例子,如果我們需要支援分頁功能,而分頁的資訊是透過 URL 查詢參數來控制的,例如: ```typescript= // 取得 10 筆使用者資料,跳過前面 20 筆 https://dummyjson.com/users?limit=10&skip=20 ``` 可以修改 resource 的定義,使其支援動態的 URL 參數。關鍵在於:傳入一個函式作為參數,而不是單純的字串 URL: ```typescript= resource = httpResource<UserList>(() => ({ url: `https://json.com/users?limit=${this.pageSize()}&skip=${this.pageSize() * this.page()}` })); ``` 這個範例中,pageSize() 和 page() 都是 Signals,它們的值綁定在一個表單上,使用者可以透過按鈕或下拉選單來變更這些參數: HTML : ```typescript= <div class="controls"> 每頁筆數: <select [(ngModel)]="pageSize"> <option>5</option> <option>10</option> <option>20</option> </select> - <button (click)="previousPage()">< 上一頁</button> 第 {{page() + 1}} 頁 / 共 {{totalPages()}} 頁 <button (click)="nextPage()">下一頁 ></button> </div> ``` 這整個流程在於:當使用者點擊「下一頁」按鈕時,我們只需要更新一個 Signal 的值: ```typescript= nextPage() { this.page.update((page) => page + 1); } ``` 由於 page() 是httpResource 的依賴之一,每次它的值變動時,就會自動重新發送 HTTP 請求以取得最新資料,這就像使用 computed signal 一樣直覺又強大。 範例連結:https://stackblitz.com/edit/ng-http-resource-pagination?file=src%2Fglobal_styles.css ## 想使用 HTTP POST 而不是 GET 怎麼辦? 可以這麼做。當然,它適用於所有類型的 HTTP 請求: ```typescript= resource = httpResource<UserList>(() => ({ url: `https://json.com/users?limit=${this.pageSize()}&skip=${this.pageSize() * this.page()}`, method: "POST" }) ); ``` ## 如果我的請求中包含動態的 body 或 headers? 很簡單——使用 Signals 就對了!只要這些 Signals 的值有任何變動,就會自動觸發新的 HTTP 請求: ```typescript= resource = httpResource<UserList>(() => ({ url: "api/schools/collection/filter", method: "POST", body: { pageSize: this.pageSize(), page: this.page() } })); ``` 同樣的概念也適用於 headers、params、URL 等其他部分。只要這些欄位中使用的是 Signal,它們的變化就會驅動 resource 重新執行請求。 以下是 HttpResourceRequest 物件所支援的所有選項,也是傳給 httpResource 函式的參數: ![image](https://hackmd.io/_uploads/Sy3QOac-le.png) 值得注意的是,可以手動觸發 resource 的重新載入,並且如果在前一個請求尚未完成時又發起新的請求,httpResource 會自動中止上一個尚未完成的 HTTP 請求。 雖然 httpResource API 目前仍屬於實驗性功能,但它極有可能在不久的將來取代我們所有對 HttpClient 的使用方式——也正因如此,和大家分享這項新功能! >資料來源出處[Signals + HTTP = httpResource [Tutorial]] >https://blog.angulartraining.com/signals-http-httpresource-tutorial-bf8792e9bda0