Reactividad Declarativa con resource()
, rxResource()
y httpResource()
en Angular
Introducción: Un nuevo paradigma en la reactividad de Angular
Angular está viviendo una de sus transformaciones más importantes desde la introducción de Ivy. Con Angular v17 y especialmente v18/v19, el framework ha empezado a adoptar un enfoque mucho más declarativo y reactivo, alejándose del tradicional modelo basado en RxJS y async pipe
como eje central de la reactividad.
Las nuevas APIs resource()
, rxResource()
y httpResource()
son un ejemplo claro de este cambio. Diseñadas para manejar flujos asincrónicos de datos de forma declarativa, estas APIs permiten simplificar la lógica de datos en componentes, reducir boilerplate y aprovechar el nuevo sistema de signals de Angular.
Este artículo explora a fondo estas APIs, con ejemplos prácticos y comparaciones, para ayudarte a comprender cuándo, por qué y cómo usarlas de forma efectiva.
resource()
: Reactividad declarativa con Promesas
La función resource()
es la forma más sencilla de integrar flujos asincrónicos (basados en Promesas) dentro del sistema de signals de Angular.
Uso básico de resource()
import { signal, resource } from '@angular/core';
const userId = signal(42);
const userResource = resource({
params: () => ({ id: userId() }),
loader: async ({ params }) => {
const res = await fetch(`/api/users/${params.id}`);
return res.json();
},
});
Acceso a estados reactivos
const user = computed(() => userResource.value());
const loading = computed(() => userResource.status() === 'loading');
const error = computed(() => userResource.error());
Esta declaración permite que Angular se encargue de manejar estados de carga, cancelación, errores y la reactividad sin necesidad de suscripciones o async pipe
.
rxResource()
: Flujos RxJS reactivos en el mundo de Signals
rxResource()
permite envolver un Observable y convertirlo en una resource reactiva, combinando lo mejor de RxJS con el sistema de signals.
Ejemplo práctico con HttpClient
import { inject } from '@angular/core';
import { rxResource } from '@angular/core/rxjs-interop';
import { HttpClient } from '@angular/common/http';
const http = inject(HttpClient);
const searchTerm = signal('');
const searchResults = rxResource({
params: () => searchTerm(),
loader: (term) => http.get(`/api/search?q=${term}`),
});
Ventajas de rxResource()
- Compatible con servicios existentes que retornan observables
- Cancelación automática cuando cambian los parámetros
- Integración directa con operadores de RxJS
httpResource()
: Declaración más simple para operaciones HTTP
Si estás usando HttpClient
y necesitas una resource, httpResource()
simplifica la sintaxis eliminando la necesidad de definir el loader manualmente.
import { httpResource } from '@angular/core';
const userId = signal(1);
const userResource = httpResource({
params: () => ({ id: userId() }),
url: ({ params }) => `/api/users/${params.id}`,
});
Características clave
- Usa internamente
HttpClient
- Incluye cancelación, manejo de errores y estados reactivos
- Requiere menos configuración
Comparación de las tres APIs
Característica | resource() |
rxResource() |
httpResource() |
---|---|---|---|
Fuente de datos | Promesa | Observable RxJS | HttpClient |
Estados (loading/error) | ✓ | ✓ | ✓ |
Cancelación automática | ✓ | ✓ | ✓ |
Integración RxJS | Parcial | Total | Parcial |
Sintaxis simplificada | Media | Media | Alta |
Ideal para | Carga remota | Streams continuos | APIs REST simples |
Casos de uso reales
Búsquedas reactivas
const query = signal('');
const results = resource({
params: () => ({ q: query() }),
loader: async ({ params }) => {
return fetch(`/api/search?q=${params.q}`).then(res => res.json());
}
});
Paginación
const page = signal(1);
const pageSize = signal(10);
const paginatedData = rxResource({
params: () => ({ page: page(), size: pageSize() }),
loader: ({ page, size }) => http.get(`/api/data?page=${page}&size=${size}`),
});
Formularios y edición
Puedes usar resource().refresh()
tras guardar los cambios para volver a cargar la data desde el servidor.
const userResource = resource(...);
async function saveChanges(user: User) {
await http.put(`/api/users/${user.id}`, user);
userResource.refresh();
}
Ventajas frente a enfoques tradicionales
- Eliminan la necesidad de
async pipe
- No requieren
subscribe()
manual ni destrucción de observables - Simplifican la composición de lógica reactiva
- Mejoran la legibilidad y mantenibilidad
Conclusión
Las APIs resource()
, rxResource()
y httpResource()
representan un cambio fundamental hacia una arquitectura declarativa y basada en signals en Angular. Aunque aún están en fase experimental, su adopción ofrece una experiencia de desarrollo moderna, con menos boilerplate, mejor manejo de estado y cancelación automática de solicitudes.
Estas herramientas permiten a los desarrolladores escribir aplicaciones más limpias, predecibles y fácilmente testeables. A medida que Angular sigue evolucionando, adoptar este paradigma puede ofrecer ventajas competitivas y mayor escalabilidad en proyectos de mediano y largo plazo.
Top comments (0)