iT邦幫忙

1

在 Resource API 中提供預設值

  • 分享至 

  • xImage
  •  

Resource API 包括 resourcerxResource 函數,其預設值未定義。當開發人員僅提供一個 loader 時,函數的傳回類型為 T | undefined。在 Angular 19.2.0 中,Resource API 將新增一個覆蓋 undefined 的 defaultValue 選項,且函數傳回類型 T。

在這篇文章中,我將向您展示如何使用 defaultValue 選項在 rxResource 函數中傳回一個虛擬 Person 物件。

向 Resource API 新增 defaultValue 選項

使用 rxResource 檢索星際大戰詳細信息

export function getPerson() {
 assertInInjectionContext(getPerson);
 const http = inject(HttpClient);
 return (id: number) => {
   return http.get<Person>(`https://swapi.dev/api/people/${id}`).pipe(
     delay(500),
     map((p) => ({...p, id } as Person)),
     catchError((err) => {
       console.error(err);
       return throwError(() => err);
     }));
 }
}

getPerson 函數呼叫 endpoint 來檢索星際大戰角色。如果 HTTP request 拋出錯誤,函數會捕獲該錯誤,記錄錯誤訊息,然後重新拋出它。 HTTP request 增加 500 毫秒的延遲來模擬長時間資源載入。

const DEFAULT: Person = {
 id: -1,
 name: 'NA',
 height: 'NA',
 mass: 'NA',
 hair_color: 'NA',
 skin_color: 'NA',
 eye_color: 'NA',
 gender: 'NA',
 films: [],
}

export function getStarWarsCharacter(id: Signal<number>, injector: Injector) {
 return runInInjectionContext(injector, () => {
   const getPersonFn = getPerson();
   const starWarsResource = rxResource({
     request: id,
     loader: ({ request: searchId }) => getPersonFn(searchId),
     defaultValue: DEFAULT
   }).asReadonly();

   return computed(() => ({
     value: starWarsResource.value(),
     status: starWarsResource.status(),
   }));
 });
}

getStarWarCharacter 函數建立一個透過 ID 查詢星際大戰角色的 resource。此資源有一個新的defaultValue 屬性,當資源未定義、正在載入或出現錯誤時,該屬性會傳回虛擬的 Person 物件。此函數傳回由資源狀態和資源值組成的計算訊號。

重構 CharacterComponent

export class CharacterComponent {
 searchId2 = signal(initialId);
 injector = inject(Injector);
 person = getStarWarsCharacter(this.searchId2, this.injector);
}

使用 rxResource,我成功地從 CharacterComponent 元件中的後端伺服器查詢了星際大戰角色。

<h3>Display one of the 83 Star War Characters</h3>
<div class="border">
  <p>Resource Status: {{ person().status }}</p>
  <app-character-info [info]="person().value" />
</div>
<app-character-picker (newSearchId)="searchId2.set($event)" />

CharacterComponent 元件顯示資源狀態,並將星際大戰角色傳遞到 CharacterInfoComponent 元件。 CharacterPickerComponent 元件會改變 ID 並將其傳送給父元件。。

重構 CharacterInfoComponent

@Component({
 selector: 'app-character-info',
 standalone: true,
 template: `
   @let person = info();
   <p>Id: {{ person.id }} </p>
   <p>Name: {{ person.name }}</p>
 `,
 changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CharacterInfoComponent {
   info = input.required<Person>();
}

CharacterInfoComponent 是一個接受星際大戰角色的 ID 和詳細資訊的元件。 我將模板邏輯移到一個新元件,使得 ChartacterComponent 看起來更簡潔。

rxResource 函數使用 defaultValue 選項傳回一個虛擬的 Person 物件;因此,info signal input 永遠不會未定義。 signal input 的類型是 Person,範本不需要檢查 info 是否未定義。

重構 CharactePickerComponent

<div class="container">
     <button (click)="delta.set({ value: -1 })">-1</button>
     <button (click)="delta.set({ value: 1 })">+1</button>
</div>
export class CharacterPickerComponent {
   newSearchId = output<number>();
   delta = signal<{ value: number }>({ value: 0 });
   characterId = linkedSignal<{ value: number }, number>({
      source: this.delta,
      computation: ({ value }, previous) => {
         const previousValue = !previous ? initialId : previous.value;
         return previousValue + value;
      }
   });
}

delta 訊號接收到新值時,characterId 訊號會增加或減少目前 ID 以得出新的 ID。

在建構函式中,effect 的回呼函數將 characterId LinkedSignal 的值發射給父元件。 Angular 團隊表示 LinkedSignal 的 computation 函數應該是 pure 的;因此,它並不是一個釋放價值的好地方。

constructor() {
    effect(() => this.newSearchId.emit(this.characterId()));
}

當使用者點擊按鈕增加或減少ID時,rxResource函數從後端伺服器載入資料時會顯示預設值。 使用者介面顯示資源狀態2,枚舉值為「Loading」。資料取得完成後進行顯示,且資源狀態變為4,即「Resolved」的枚舉值。當使用者將ID改為17時,HTTP請求會拋出例外。資源狀態變成1,「Error」枚舉值,顯示預設值。

defaultValue 選項允許開發人員為 Resource API 提供 undefined 以外的預設值。當資源必須傳回 T 而不是 T | undefined 時,這很有幫助的。當物件可能為 null 時,不需要額外的程式碼來解構屬性並指派預設值。

參考:


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言