Las Runes en Svelte son el sistema de reactividad introducido en Svelte 5.
Son objetos especiales que almacenan y administran valores reactivos de manera más eficiente que los anteriores stores.
Permiten declarar variables reactivas usando la sintaxis $ (por ejemplo: let $count = 0), y cualquier cambio en su valor actualiza automáticamente todos los componentes que lo utilizan.
$props(): son inmutables y se usan para recibir datos del componente padre$state(): es perfecto para datos que cambian con el tiempo$derived(): calcula valores automáticamente basándose en otros estados$effect(): es ideal para manejar efectos secundarios como llamadas API o persistencia$props)Los props son valores que se pasan desde el componente padre y son inmutables por defecto
Esta rune permite acceder y reaccionar a las propiedades (props) que recibe un componente.
Ejemplo 1: Props básicos para un componente de botón
const buttonProps = $props();
const label = buttonProps.label || 'Botón';
const variant = buttonProps.variant || 'primary'; <button class={variant}>
{label}
</button> label y variant se obtienen con valores predeterminados en caso de que no sean proporcionados.Ejemplo 2: Props con validación
const userProps = $props((props) => {
if (!props.name || !props.email || typeof props.age !== 'number') {
throw new Error('Props inválidos: se requieren name, email y age como número.');
}
if (props.age < 0) {
throw new Error('La edad debe ser un número positivo.');
}
return props;
}); <p>Nombre: {userProps.name}</p>
<p>Edad: {userProps.age}</p>
<p>Email: {userProps.email}</p> name, age y email sean válidos antes de usarlos en el componente.Ejemplo 3: Props con valores por defecto
const cardProps = $props({
title: 'Título por defecto',
description: 'Sin descripción proporcionada',
image: null,
});
const { title, description, image } = cardProps; <div class="card">
<h1>{title}</h1>
<p>{description}</p>
{#if image}
<img src={image} alt={title} />
{/if}
</div> {#if image} asegura que solo se renderice la imagen si está definida.Ejemplo 4: Acceder y mostrar todas las props de un componente:
Puedes usar $props() para acceder dinámicamente a todas las propiedades que se pasan al componente.
<script>
import { $props } from 'svelte';
const props = $props();
</script>
<h1>Props recibidas:</h1>
<ul>
{#each Object.entries(props) as [key, value]}
<li>{key}: {value}</li>
{/each}
</ul> <!-- Uso -->
<Componente nombre="Svelte" version="5" />
<!--Muestra todas las props con sus valores en forma de lista.---> Ejemplo 5: Reaccionar dinámicamente al cambio de props:
Usa el ciclo de vida afterUpdate para reaccionar dinámicamente al cambio de props, actualizando el estado interno o ejecutando lógica cuando cambien.
<script>
import { afterUpdate } from 'svelte';
export let nombre;
afterUpdate(() => {
console.log(`Prop nombre cambió a: ${nombre}`);
});
</script>
<h1>Hola, {nombre}!</h1>
<!-- Uso -->
<Componente nombre="Svelte" />
<!-- Cuando la prop `nombre` cambia, `afterUpdate` se ejecuta y registra el nuevo valor.--> Ejemplo 6: Combinar $props() con valores predeterminados: Establece valores predeterminados para props opcionales si no se pasan.
<script>
import { $props } from 'svelte';
const props = $props();
const nombre = props.nombre || 'Desarrollador';
const edad = props.edad || 25;
</script>
<h1>Hola, {nombre}!</h1>
<p>Tu edad es {edad} años.</p>
<!-- Uso -->
<Componente nombre="Svelte" />
<!-- Si no se pasa edad, usará 25 como predeterminado --> Si una prop no se pasa, se usa el valor predeterminado.
Variable reactiva $count que se incrementa en 1 y actualiza automáticamente toda la UI donde se use.
// 1. Contador básico
let $count = 0;
function increment() {
$count++;
} Estado reactivo $isVisible que alterna entre true/false para controlar la visibilidad de elementos en la UI.
// 2. Toggle booleano
let $isVisible = false;
function toggle() {
$isVisible = !$isVisible;
} Objeto $user con propiedades reactivas que mantiene sincronizada la UI cuando se modifica cualquier propiedad.
// 3. Objeto reactivo
let $user = {
name: 'Ana',
age: 25
};
function updateAge() {
$user.age++;
} Array $todos que mantiene una lista de tareas y se actualiza de forma inmutable para preservar la reactividad.
// 4. Lista reactiva
let $todos = [];
function addTodo(text) {
$todos = [...$todos, { text, completed: false }];
} Combina reactivamente $firstName y $lastName para crear $fullName que se actualiza cuando cambia cualquier nombre.
// 5. Valor derivado (computed)
let $firstName = 'Juan';
let $lastName = 'Pérez';
let $fullName = $derived(`${$firstName} ${$lastName}`); Campo $email con validación reactiva que verifica automáticamente el formato cada vez que cambia el valor.
// 6. Estado con validación
let $email = '';
let $isValid = $derived(() => {
return $email.includes('@') && $email.length > 5;
}); $derived) para Estados DerivadosCon $derived, puedes crear estados que dependan de otros, recalculándose automáticamente cuando los estados originales cambian.
En conclusión con runes $derived, podemos calcular valores automáticamente a partir de otros estados.
Ejemplo 1: Valor derivado simple
let price = $state(100)
let tax = $state(0.21)
let totalPrice = $derived(price + (price * tax)) Calcula el precio total incluyendo impuestos automáticamente
Ejemplo 2: Lista filtrada
let items = $state(['manzana', 'banana', 'cereza'])
let searchTerm = $state('')
let filteredItems = $derived(
items.filter(item => item.includes(searchTerm))
) Filtra una lista basada en un término de búsqueda
Ejemplo 3: Estadísticas
let scores = $state([75, 80, 95, 70])
let average = $derived(
scores.reduce((a, b) => a + b, 0) / scores.length
) Calcula el promedio de una lista de puntuaciones
Ejemplo 4: Cálculo Automático con $derived en Listas
let numbers = $state([1, 2, 3, 4]);
let total = $derived(numbers.reduce((t, n) => t + n, 0)); Ahora podemos usar esto en nuestro marcado:
<p>{numbers.join(' + ')} = {total}</p> La expresión dentro de la declaración $derived se volverá a evaluar cada vez que numbers actualice sus dependencias.
A diferencia del estado normal ($state), el estado derivado es de solo lectura.
Ejemplo 5: Cálculo Automático con $derived en Svelte
Archivo: store.js:
import { $state, $derived } from 'svelte';
export const basePrice = $state(100);
export const quantity = $state(2);
export const totalPrice = $derived(() => basePrice.get() * quantity.get()); Uso en el Componente App.svelte:
<script>
import { basePrice, quantity, totalPrice } from './store.js';
</script>
<p>Precio Base: {basePrice}</p>
<p>Cantidad: {quantity}</p>
<p>Precio Total: {totalPrice}</p>
<button on:click={() => quantity.set(quantity.get() + 1)}>Incrementar Cantidad</button> $effect) para Efectos SecundariosLa rune $effect ejecuta código automáticamente cuando un estado cambia.
Es decir permite ejecutar efectos secundarios cuando un estado cambia.
Ejemplo 1: Logging de cambios
let username = $state('')
$effect(() => {
console.log(`Username changed to: ${username}`)
}) Registra cambios en el nombre de usuario
Ejemplo 2: Persistencia local
let preferences = $state({ theme: 'light' })
$effect(() => {
localStorage.setItem('preferences', JSON.stringify(preferences))
}) Guarda preferencias en localStorage cuando cambian
Ejemplo 3: Llamadas API
let userId = $state(null)
$effect(() => {
if (userId) {
fetch(`/api/users/${userId}`)
.then(response => response.json())
.then(data => console.log(data))
}
}) Realiza una llamada API cuando cambia el ID del usuario
Ejemplo 2: Seguimiento de Cambios con $effect en Svelte
Archivo: logger.js:
import { $effect } from 'svelte';
import { globalCount } from './store.js';
$effect(() => {
console.log('El contador global cambió a:', globalCount.get());
}); Uso en el Componente App.svelte:
<script>
import './logger.js';
import { globalCount } from './store.js';
</script>
<button on:click={() => globalCount.set(globalCount.get() + 1)}>Incrementar</button> Las runes en Svelte también se pueden usar fuera de los componentes para manejar estados globales, acciones compartidas o cualquier funcionalidad que necesite ser accesible en múltiples partes de tu aplicación.
$state) para un Estado GlobalLa rune $state nos permite crear estados globales accesibles desde cualquier parte de la aplicación.
En conclusión runes $state representa un estado local reactivo que puede cambiar durante la vida del componente
Ejemplo 1: Contador simple
let count = $state(0)
function increment() {
count++
} Estado básico para un contador interactivo
Ejemplo 2: Estado de formulario
let formData = $state({
username: '',
password: '',
isValid: false
}) Maneja múltiples campos de formulario en un solo estado
Ejemplo 3: Estado de toggle
let isOpen = $state(false)
function toggle() {
isOpen = !isOpen
} Control de estado booleano para mostrar/ocultar elementos