¿Qué son los Signals?
Los Signals son un sistema de reactividad nativo de Angular que proporciona una forma moderna y eficiente de manejar el estado de los componentes. A diferencia de las variables tradicionales, los signals son primitivas reactivas que notifican automáticamente cuando su valor cambia, permitiendo que la interfaz de usuario se actualice de manera automática y optimizada.
Concepto fundamental
Un signal es esencialmente un contenedor que almacena un valor y puede notificar a otros elementos cuando ese valor cambia. Piensa en él como una variable especial que "sabe" cuando ha sido modificada y puede avisar a quien esté interesado en esos cambios.
Los signals representan la evolución natural de la reactividad en Angular. Mientras que anteriormente dependíamos principalmente de RxJS para manejar datos reactivos, los signals ofrecen una alternativa más simple y directa para el manejo de estado local de componentes.
Creación básica de signals
Para crear un signal, utilizamos la función signal()
importada desde @angular/core
:
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-contador',
template: `
<h2>Contador: {{ contador() }}</h2>
<p>Usuario: {{ nombreUsuario() }}</p>
<p>Está activo: {{ estaActivo() }}</p>
`
})
export class ContadorComponent {
// Signal con valor numérico
contador = signal(0);
// Signal con string
nombreUsuario = signal('Juan Pérez');
// Signal con boolean
estaActivo = signal(true);
}
Lectura de signals
Para leer el valor de un signal, debemos llamarlo como si fuera una función. Esto es importante: los signals se leen utilizando paréntesis ()
:
export class EjemploComponent {
precio = signal(29.99);
producto = signal('Camiseta');
ngOnInit() {
// Leer valores en el componente
console.log('Precio actual:', this.precio());
console.log('Producto:', this.producto());
// Los signals se pueden usar en cálculos
const precioConIva = this.precio() * 1.21;
console.log('Precio con IVA:', precioConIva);
}
}
En el template, los signals también se leen con paréntesis:
<div class="producto">
<h3>{{ producto() }}</h3>
<p class="precio">{{ precio() }}€</p>
<div class="total">
Total con IVA: {{ precio() * 1.21 }}€
</div>
</div>
Ventajas de los signals
Los signals ofrecen varias ventajas importantes:
- Rendimiento optimizado: Angular solo actualiza las partes de la interfaz que realmente han cambiado
- Sintaxis más simple: No necesitas suscripciones ni gestión manual de observables para estado local
- Detección automática: Angular detecta automáticamente cuando un signal cambia y actualiza la vista
- Menos boilerplate: Reduce la cantidad de código necesario comparado con RxJS para casos simples
Diferencia con variables tradicionales
Comparemos una variable tradicional con un signal:
export class ComparacionComponent {
// Variable tradicional - NO reactiva
contadorTradicional = 0;
// Signal - SÍ reactiva
contadorSignal = signal(0);
incrementar() {
// Cambio en variable tradicional - Angular NO se entera automáticamente
this.contadorTradicional++;
// Cambio en signal - Angular detecta el cambio automáticamente
this.contadorSignal.set(this.contadorSignal() + 1);
}
}
En el template:
<!-- Estas dos líneas se comportan diferente -->
<p>Contador tradicional: {{ contadorTradicional }}</p>
<p>Contador signal: {{ contadorSignal() }}</p>
Cuando cambia contadorTradicional
, Angular puede no detectar el cambio inmediatamente. Cuando cambia contadorSignal
, Angular actualiza automáticamente la interfaz de manera optimizada.
Cuándo usar signals
Los signals son ideales para:
- Estado local del componente que cambia frecuentemente
- Valores que se muestran directamente en el template
- Datos que necesitan actualizarse automáticamente en la interfaz
- Situaciones donde quieres evitar la complejidad de RxJS para casos simples
Los signals representan el futuro de la reactividad en Angular, proporcionando una forma más intuitiva y eficiente de manejar el estado de nuestras aplicaciones.
Crear y leer signals básicos
La creación y lectura de signals constituye la base fundamental para trabajar con reactividad nativa en Angular. Dominar estas operaciones básicas te permitirá aprovechar al máximo el sistema de signals en tus componentes.
Sintaxis de creación
Para crear un signal, importamos la función signal
desde @angular/core
y la utilizamos para inicializar nuestras variables reactivas:
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-tienda',
standalone: true,
template: `
<div class="tienda">
<h2>{{ titulo() }}</h2>
<p>Productos disponibles: {{ stock() }}</p>
</div>
`
})
export class TiendaComponent {
titulo = signal('Mi Tienda Online');
stock = signal(150);
}
Tipos de datos en signals
Los signals pueden almacenar cualquier tipo de dato de TypeScript, desde primitivos hasta objetos complejos:
1 - Valores primitivos:
export class DatosBasicosComponent {
// Números
edad = signal(25);
precio = signal(19.99);
// Strings
nombre = signal('María');
mensaje = signal('');
// Booleans
activo = signal(true);
cargando = signal(false);
}
2 - Arrays y objetos:
export class DatosComplejosComponent {
// Arrays
colores = signal(['rojo', 'azul', 'verde']);
numeros = signal([1, 2, 3, 4, 5]);
// Objetos
usuario = signal({
id: 1,
nombre: 'Ana',
email: 'ana@email.com'
});
// Arrays de objetos
productos = signal([
{ id: 1, nombre: 'Laptop', precio: 999 },
{ id: 2, nombre: 'Mouse', precio: 25 }
]);
}
Lectura en el componente
Para acceder al valor de un signal dentro del componente, utilizamos la sintaxis de llamada a función con paréntesis:
export class LecturaComponent {
contador = signal(10);
nombre = signal('Pedro');
mostrarDatos() {
// Leer valores individuales
const valorContador = this.contador();
const valorNombre = this.nombre();
console.log(`El contador está en: ${valorContador}`);
console.log(`El usuario es: ${valorNombre}`);
// Usar en operaciones
const doble = this.contador() * 2;
const saludo = `Hola, ${this.nombre()}!`;
console.log(`El doble es: ${doble}`);
console.log(saludo);
}
}
Lectura en templates
En los templates HTML, los signals se leen de la misma manera, utilizando la sintaxis de interpolación con paréntesis:
<div class="perfil-usuario">
<!-- Interpolación simple -->
<h1>Bienvenido {{ nombreUsuario() }}</h1>
<p>Puntos acumulados: {{ puntos() }}</p>
<!-- En expresiones -->
<p>Descuento disponible: {{ puntos() >= 100 ? '10%' : 'No disponible' }}</p>
<!-- En cálculos -->
<p>Total con descuento: {{ precio() * 0.9 }}€</p>
<!-- Con métodos de array -->
<p>Primer color favorito: {{ coloresFavoritos()[0] }}</p>
<p>Cantidad de colores: {{ coloresFavoritos().length }}</p>
</div>
Patterns de lectura comunes
Algunos patrones frecuentes para trabajar con signals en templates:
1 - Condicionales basadas en signals:
<div class="estado">
@if (estaConectado()) {
<span class="online">Usuario conectado</span>
} @else {
<span class="offline">Usuario desconectado</span>
}
</div>
2 - Iteración sobre arrays signals:
<ul class="lista-tareas">
@for (tarea of tareas(); track tarea.id) {
<li>{{ tarea.nombre }} - {{ tarea.completada() ? 'Hecha' : 'Pendiente' }}</li>
}
</ul>
3 - Binding de propiedades:
<input
type="text"
[placeholder]="mensajePlaceholder()"
[disabled]="formularioDeshabilitado()">
<button
type="button"
[class.active]="botonActivo()">
{{ textoBoton() }}
</button>
Ejemplo práctico completo
Veamos un ejemplo integrador que muestra la creación y lectura de signals en un componente real:
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-perfil',
standalone: true,
template: `
<div class="perfil">
<header>
<h1>{{ nombre() }}</h1>
<p>{{ profesion() }}</p>
</header>
<main>
<div class="estadisticas">
<div class="stat">
<span class="numero">{{ experiencia() }}</span>
<span class="label">años de experiencia</span>
</div>
<div class="stat">
<span class="numero">{{ proyectos().length }}</span>
<span class="label">proyectos completados</span>
</div>
</div>
<div class="disponibilidad">
@if (disponible()) {
<span class="badge disponible">Disponible</span>
} @else {
<span class="badge ocupado">Ocupado</span>
}
</div>
</main>
</div>
`
})
export class PerfilComponent {
// Signals básicos
nombre = signal('Laura García');
profesion = signal('Desarrolladora Frontend');
experiencia = signal(5);
disponible = signal(true);
// Signal con array
proyectos = signal([
'E-commerce React',
'Dashboard Angular',
'App móvil Ionic'
]);
// Método que usa signals
mostrarResumen() {
const resumen = `
${this.nombre()} es ${this.profesion().toLowerCase()}
con ${this.experiencia()} años de experiencia.
Ha completado ${this.proyectos().length} proyectos.
Estado: ${this.disponible() ? 'Disponible' : 'Ocupado'}
`;
console.log(resumen);
}
}
Ventajas de la sintaxis de lectura
La sintaxis con paréntesis para leer signals ofrece varias ventajas:
- Claridad: Es evidente que estás accediendo a un valor reactivo
- Consistencia: Mismo patrón tanto en componentes como en templates
- Optimización: Angular puede rastrear automáticamente las dependencias
- Type safety: TypeScript puede inferir correctamente los tipos
Esta base sólida en creación y lectura de signals te prepara para trabajar con funcionalidades más avanzadas del sistema de reactividad de Angular en lecciones posteriores.
Fuentes y referencias
Documentación oficial y recursos externos para profundizar en Angular
Documentación oficial de Angular
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Angular es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de Angular
Explora más contenido relacionado con Angular y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
- Comprender qué son los signals y su función en Angular.
- Aprender a crear y leer signals básicos en componentes y templates.
- Diferenciar entre variables tradicionales y signals en términos de reactividad.
- Identificar las ventajas de usar signals para el manejo del estado local.
- Aplicar patrones comunes de lectura y uso de signals en Angular.