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 時,不需要額外的程式碼來解構屬性並指派預設值。