Skip to content

Commit 0814ee3

Browse files
authored
feat(resource): add post on Angular resource and rxResource API (#32)
1 parent 0235b14 commit 0814ee3

File tree

1 file changed

+144
-0
lines changed

1 file changed

+144
-0
lines changed
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
---
2+
date: 2025-02-09
3+
title: Angular resource and rxResource API
4+
description: Angular v19 introduces a powerful new API for handling asynchronous data the `resource` and `rxResource` APIs. These new primitives integrate seamlessly with Angular's signal-based reactivity model, making it easier to fetch, manage, and update data while keeping track of loading and error states.
5+
tags: ['angular', 'resource-api', 'signals']
6+
category: Angular
7+
---
8+
9+
Angular v19 introduces a powerful new API for handling asynchronous data: the `resource` and `rxResource` APIs. These new primitives integrate seamlessly with Angular's signal-based reactivity model, making it easier to fetch, manage, and update data while keeping track of loading and error states.
10+
11+
## Why Use the Resource API?
12+
13+
Before `resource`, developers often relied on `HttpClient` with `Observables` or `Promises` to manage async data. While this approach worked well, it required additional RxJS operators like `switchMap` to handle reactive changes effectively. The new `resource` API simplifies this by:
14+
15+
- Automatically tracking dependent signals and reloading data when they change.
16+
- Handling request cancellation to prevent race conditions.
17+
- Providing built-in methods for local updates and manual refreshes.
18+
- Offering `rxResource` for developers who prefer working with Observables.
19+
20+
## `resource`
21+
22+
```typescript
23+
import { resource, Signal } from '@angular/core';
24+
import { Component, computed, effect, signal } from '@angular/core';
25+
26+
interface MissionLog {
27+
id: number;
28+
title: string;
29+
description: string;
30+
status: 'pending' | 'completed';
31+
}
32+
33+
@Component({ selector: 'app-mission-log', templateUrl: './mission-log.component.html' })
34+
export class MissionLogComponent {
35+
missionId = signal(1);
36+
37+
missionResource = resource({
38+
request: this.missionId,
39+
loader: ({ request: id }) => fetch(`https://api.spacedata.com/missions/${id}`).then((res) => res.json()),
40+
});
41+
42+
loading = this.missionResource.isLoading;
43+
error = this.missionResource.error;
44+
45+
nextMission() {
46+
this.missionId.update((id) => id + 1);
47+
}
48+
}
49+
```
50+
51+
### Key Takeaways:
52+
53+
- `request`: Tracks the `missionId` signal so the loader fetches new data when it changes.
54+
- `loader`: Defines how the mission data is fetched.
55+
- `isLoading` and `error`: Useful for UI updates.
56+
57+
### Understanding Loaders
58+
59+
A loader is an asynchronous function that retrieves data when the `request` signal changes. Loaders receive an object with:
60+
61+
- `request`: The computed value from the `request` function.
62+
- `previous`: The previous state of the resource, which includes the last known value and status.
63+
- `abortSignal`: A signal used to cancel previous requests to avoid race conditions.
64+
65+
Example of using `abortSignal` in the loader:
66+
67+
```typescript
68+
missionResource = resource({
69+
request: this.missionId,
70+
loader: ({ request: id, abortSignal }) =>
71+
fetch(`https://api.spacedata.com/missions/${id}`, { signal: abortSignal }).then((res) => res.json()),
72+
});
73+
```
74+
75+
This ensures that if a new request is made before the previous one completes, the older request is aborted.
76+
77+
:::caution
78+
Loaders are untracked, meaning that changes inside a loader function do not trigger a re-execution of the function unless the `request` signal changes.
79+
:::
80+
81+
### Resource Status
82+
83+
The `resource` API provides several status signals to help track the loading process:
84+
85+
- `Idle` No valid request; loader hasn't run yet.
86+
- `Loading` Loader is currently running.
87+
- `Resolved` Loader has successfully completed and returned a value.
88+
- `Error` An error occurred while fetching data.
89+
- `Reloading` A new request is in progress while keeping the last successful value.
90+
- `Local` The resource was updated locally via `.set()` or `.update()`.
91+
92+
### Reloading a Resource
93+
94+
The `reload` method allows you to manually re-fetch data from the loader without changing the `request` signal. This is useful when you want to refresh the data on demand, such as when a user clicks a refresh button. Calling `reload()` will re-trigger the loader while maintaining the last known successful value until the new data is fetched.
95+
96+
```typescript
97+
refreshMission() {
98+
this.missionResource.reload();
99+
}
100+
```
101+
102+
### Updating Mission Data Locally
103+
104+
Sometimes, you need to modify data without fetching from the server again. The `resource` API allows local updates:
105+
106+
```typescript
107+
completeMission() {
108+
this.missionResource.update(mission => ({ ...mission, status: 'completed' }));
109+
}
110+
```
111+
112+
This marks the mission as completed locally, without making another API request.
113+
114+
## `rxResource`
115+
116+
For developers who prefer Observables, `rxResource` provides a reactive approach using RxJS:
117+
118+
```typescript
119+
import { rxResource } from '@angular/core/rxjs-interop';
120+
import { HttpClient } from '@angular/common/http';
121+
import { inject, signal } from '@angular/core';
122+
123+
@Component({ selector: 'app-rx-mission-log', templateUrl: './rx-mission-log.component.html' })
124+
export class RxMissionLogComponent {
125+
http = inject(HttpClient);
126+
limit = signal(5);
127+
128+
missionsResource = rxResource({
129+
request: this.limit,
130+
loader: (limit) => this.http.get<MissionLog[]>(`https://api.spacedata.com/missions?limit=${limit}`),
131+
});
132+
}
133+
```
134+
135+
This integrates seamlessly with Angular’s existing `HttpClient` and RxJS ecosystem, automatically switching to the latest request when the limit changes.
136+
137+
## Conclusion
138+
139+
The new `resource` and `rxResource` APIs are a game-changer for handling async data in Angular. They provide:
140+
141+
- Simple, declarative syntax for fetching data.
142+
- Automatic request cancellation.
143+
- Built-in support for local updates.
144+
- A smooth transition for developers using RxJS.

0 commit comments

Comments
 (0)