Runes de Svelte 5: $state, $derived, $effect, $props | We.Inc
Cada rune de Svelte 5 junto al código de Svelte 4 que sustituye: $state, $derived, $effect, $props y $bindable, más la nueva sintaxis de eventos y snippets. Ejemplos listos para copiar.
Las runes son las palabras clave del compilador que Svelte 5 usa para la reactividad. $state declara una variable reactiva, $derived calcula un valor a partir de otro estado, $effect ejecuta código después de que la página se actualice, $props lee las props del componente y $bindable marca una prop a la que el padre puede enlazarse. Sustituyen al let reactivo, a la etiqueta $: y a export let de Svelte 4.
La sintaxis de Svelte 4 y la rune que la sustituye
Tarea
Svelte 4
Svelte 5
Variable reactiva
let count = 0
let count = $state(0)
Valor calculado
$: doubled = count * 2
let doubled = $derived(count * 2)
Efecto secundario
$: console.log(count)
$effect(() => console.log(count))
Props
export let name
let { name } = $props()
Prop enlazable
export let value
let { value = $bindable() } = $props()
Manejador de eventos
on:click={fn}
onclick={fn}
Eventos de componente
createEventDispatcher
Props de callback
Slots
<slot />
{#snippet} y {@render}
Elige una rune para ver un componente de Svelte 4 y su reescritura en Svelte 5. Cada pareja se comporta igual, así que puedes migrar archivo a archivo y comprobar el resultado sobre la marcha.
Selecciona una rune o un cambio de sintaxis con los botones.
Compara el código de Svelte 4 de la izquierda con el de Svelte 5 de la derecha.
Lee la nota con la regla que suele pillar desprevenida a la gente.
Copia la versión de Svelte 5 en tu componente.
Usa $derived para todo lo que se pueda calcular. Reserva $effect para comunicarte con cosas de fuera de Svelte, como el título del documento, un canvas o un widget de terceros.
Recuerda que $effect nunca se ejecuta durante el renderizado en el servidor, así que es un lugar seguro para el código que toca window o document.
Recurre a $state.raw con arrays grandes que solo vayas a reemplazar enteros. Se salta el proxy profundo y solo se puede reasignar.
Pasa $state.snapshot(value) a las bibliotecas que esperan un objeto plano en lugar de un proxy.
Las runes también funcionan en archivos .svelte.js y .svelte.ts, lo que te permite compartir lógica reactiva fuera de los componentes.
Preguntas frecuentes
¿Tengo que reescribir toda mi app para Svelte 5?
No. Svelte 5 sigue admitiendo la sintaxis de Svelte 4, y los componentes antiguos y los basados en runes pueden convivir en la misma app y usarse entre sí, así que puedes convertir los archivos uno a uno.
¿Por qué mi $effect no se vuelve a ejecutar?
Svelte solo rastrea el estado leído de forma síncrona dentro del efecto. Un valor leído después de un await o dentro de un callback de setTimeout no es una dependencia, así que cambiarlo no hace nada.
¿Puedo cambiar un valor $derived?
Desde Svelte 5.25 puedes reasignar temporalmente un valor derivado, lo que ayuda con las actualizaciones optimistas, salvo que esté declarado con const. Se vuelve a calcular cuando cambian sus dependencias. Las versiones anteriores tratan los derivados como de solo lectura.
¿Qué sustituyó a createEventDispatcher?
Las props de callback. El hijo recibe una función como onsave mediante $props y la invoca, y el padre pasa el manejador como cualquier otro atributo.
¿Cómo doy un id único a un campo de formulario?
Usa $props.id(), añadido en Svelte 5.20. Devuelve un id único para la instancia del componente que coincide entre el servidor y el navegador, así que es seguro para for y aria-labelledby.
$state es profundo por defecto
Envolver un array o un objeto plano en $state te da un proxy profundamente reactivo. Añadir elementos al array o cambiar una propiedad anidada actualiza solo las partes de la página que la leen, sin necesidad de reasignar el valor completo.
Los campos de clase también pueden ser estado: declara un campo con $state dentro de una clase y el compilador lo convierte en un par getter y setter.
$derived debe ser puro
La expresión dentro de $derived solo debe calcular. Svelte rechaza cambios de estado como count++ dentro de ella. Para lógica más larga, $derived.by recibe una función cuyo valor de retorno se convierte en el valor derivado.
Los derivados son perezosos: Svelte los marca como obsoletos cuando cambia una dependencia y los recalcula en la siguiente lectura, saltándose el trabajo posterior cuando el resultado es el mismo.
Cuándo se ejecuta $effect y cómo limpiarlo
Un efecto se ejecuta cuando el componente se monta y de nuevo cuando cambian sus dependencias, una vez actualizado el DOM. Devuelve una función desde el efecto para limpiar temporizadores o listeners antes de la siguiente ejecución y cuando el componente se destruye.
Si necesitas medir o ajustar algo antes de que cambie el DOM, como mantener un historial de chat desplazado hasta el final, usa $effect.pre en su lugar.
Compartir estado entre componentes
Un store reactivo en un archivo .svelte.js
Una variable $state que se reasigna no se puede exportar directamente, así que exporta un objeto y cambia sus propiedades.
$state
Un let simple ya no es reactivo en modo runes. Envuelve el valor inicial en $state y actualízalo como cualquier variable.
$derived
La etiqueta $: hacía dos trabajos. Los cálculos pasan a ser $derived; Svelte los recalcula cuando cambia count.
$effect
Los efectos secundarios de $: pasan a $effect. Se ejecuta en el navegador después de actualizar el DOM, y su valor de retorno es la limpieza.
$props
Todas las props llegan en una sola desestructuración. Los valores por defecto, los renombrados y las props rest usan la sintaxis normal de JavaScript.
$bindable
Marca una prop con $bindable para que un padre pueda usar bind: sobre ella. El código del padre no cambia.
Eventos
on:click pasa a ser el atributo onclick, y los eventos personalizados se convierten en props de callback en lugar de createEventDispatcher.
Snippets
El snippet children sustituye al slot por defecto, y {@render} lo coloca. El ?. omite el renderizado cuando no se pasó ningún children.