Angular 21: el cambio de paradigma que no podés ignorar
Cuando Angular anunció que las Signals pasaban de experimental a estables, lo tomé como «otra API más para aprender». Me equivoqué. No era una API nueva: era un cambio de paradigma que afecta cómo se detectan cambios, cómo se construyen formularios, cómo funciona el router y hasta cómo escribimos los tests. Angular 21 consolida todo eso. Esta serie es lo que me hubiera gustado tener cuando arranqué la migración.
El contexto: por qué Angular cambió tan profundamente
Durante años, Angular usó Zone.js para detectar cuándo algo cambiaba en la aplicación y disparar la actualización del DOM. Zone.js intercepta todas las operaciones asíncronas — setTimeout, promesas, eventos — y notifica a Angular para que re-evalúe la vista. Funcionaba. Pero tenía un costo: bundle más grande, detección de cambios innecesaria, y comportamiento difícil de predecir en aplicaciones complejas.
Las Signals cambian el modelo de raíz: en lugar de «revisar todo cuando algo asíncrono ocurre», ahora cada valor sabe exactamente quién depende de él y notifica solo a esos dependientes. Es reactivo de verdad, no reactivo por polling.
Qué cambió de Angular 20 a Angular 21
| Área | Antes (v20) | Angular 21 |
|---|---|---|
| Detección de cambios | Zone.js por defecto | Zoneless por defecto en proyectos nuevos |
| Formularios | FormGroup / FormControl | Signal Forms: form() y field() |
| Router | Inyección de Router class | Funciones standalone con Signals |
| Testing | Karma + Jasmine | Vitest por defecto |
| Template | Sintaxis estándar | Regex literals, spread operator, instanceof |
| Tooling IA | Manual | Soporte MCP nativo (ng mcp) |
| HTTP | HttpClient observable | httpResource con Signals |
httpResource: el nuevo cliente HTTP basado en Signals
Una de las novedades más destacadas de v21.2: httpResource. La respuesta de Angular a «¿cómo hago una llamada HTTP y el resultado sea un Signal?»
import { Component, signal } from '@angular/core';
import { httpResource } from '@angular/common/http';
@Component({
selector: 'app-usuarios',
template: `
@if (usuarios.isLoading()) {
<p>Cargando...</p>
} @else if (usuarios.error()) {
<p>Error: {{ usuarios.error()?.message }}</p>
} @else {
<ul>
@for (u of usuarios.value(); track u.id) {
<li>{{ u.nombre }}</li>
}
</ul>
}
`
})
export class UsuariosComponent {
// Sin subscribe, sin async pipe — el resultado es un Signal
usuarios = httpResource<Usuario[]>('/api/usuarios');
// Con parámetros reactivos: se re-fetcha cuando cambia el signal
filtro = signal('admin');
usuariosFiltrados = httpResource<Usuario[]>(() =>
`/api/usuarios?rol=${this.filtro()}`
);
}
La hoja de ruta de esta serie
- Este artículo: el panorama general del salto v20 → v21
- Adiós Zone.js: detección de cambios Zoneless en profundidad
- Signal Forms: formularios reactivos que finalmente tienen sentido
- Novedades del template: regex, spread, instanceof y más
- Vitest reemplaza Karma + soporte MCP nativo
- Router Signals: navegación standalone sin cargar todo el Router
- Guía práctica de migración de Angular 19/20 a Angular 21.2
Si estás trabajando con Angular en proyectos .NET — como yo, donde el backend es ASP.NET y el frontend es Angular — estos cambios son especialmente relevantes. La adopción de Signals reduce considerablemente el gap conceptual entre el modelo reactivo del frontend y los patrones async/await del backend. Empecemos.
Serie Angular 20 → 21.2 | Próximo: Adiós Zone.js: cómo Angular 21 cambió la detección de cambios para siempre →

Dejar un comentario
¿Quieres unirte a la conversación?Siéntete libre de contribuir!