Resource API 包括 resource 和 rxResource 函數,其預設值未定義。當開發人員僅提供一個 loader 時,函數的傳回類型為 T | undefined。在 Angular 19.2.0 中,Resource API 將新增一個覆蓋 undefined 的 defaultValue 選項,且函數傳回類型 T。
在這篇文章中,我將向您展示如何使用 defaultValue 選項在 rxResource 函數中傳回一個虛擬 Person 物件。
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 物件。此函數傳回由資源狀態和資源值組成的計算訊號。
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 並將其傳送給父元件。。
@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 是否未定義。
<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 時,不需要額外的程式碼來解構屬性並指派預設值。