Svelte 5 está a punto de llegar y con él vienen cambios que van a transformar la forma en que manejamos eventos, estado y propiedades en nuestros componentes. Aunque todavía no sabemos la fecha exacta de lanzamiento, ya podemos ir preparándonos para adaptar nuestro código a esta nueva versión que promete simplificar y modernizar la experiencia de desarrollo.
Uno de los cambios más visibles será la forma en que declaramos los manejadores de eventos. Hasta ahora, en Svelte usábamos la sintaxis on:evento, como on:click o on:blur. En Svelte 5, esta sintaxis se simplifica eliminando los dos puntos, por lo que ahora escribiremos directamente onClick, onMouseMove, onEnter, etc. Esto hace que los eventos se traten como props normales que se pasan a los componentes, lo que abre la puerta a una escritura más cómoda y coherente. Por ejemplo, si tenemos una función llamada onClick, podemos pasarla directamente como prop sin necesidad de asignarla explícitamente con un igual, simplemente usando {onClick}.
Este cambio también implica que la función createEventDispatcher, que usábamos para emitir eventos personalizados desde componentes hijos hacia padres, queda deprecada. En su lugar, se adopta un patrón más parecido al de React: pasamos funciones como props para manejar eventos. Por ejemplo, un componente Pump podría recibir dos props, inflate y deflate, que son funciones que el componente invoca cuando ocurren ciertos eventos internos. Así, el componente padre controla qué hacer cuando se disparan esos eventos, sin necesidad de crear dispatchers personalizados.
Esta nueva forma de manejar eventos también significa que los modificadores como once o preventDefault desaparecen. Si queremos que un evento se ejecute solo una vez, tendremos que implementar esa lógica manualmente dentro del manejador, por ejemplo, devolviendo una función que se desasigne a sí misma tras la primera ejecución. Para evitar que el evento realice su acción por defecto, ahora tendremos que llamar explícitamente a e.preventDefault() dentro del manejador. Aunque esto dispersa un poco la lógica, la ventaja es que toda la información del evento queda centralizada en el manejador mismo.
Otro cambio interesante son los Snippets, una nueva forma de organizar componentes complejos sin necesidad de crear múltiples archivos. Si alguna vez hemos tenido un componente muy grande con varios bucles o secciones repetitivas, probablemente hemos creado componentes hijos para mantener el código limpio, pero esto puede generar muchos archivos y complicar la estructura. Con los Snippets, podemos definir componentes anónimos dentro del mismo archivo usando la etiqueta Snippet y asignándoles un nombre, por ejemplo, Figure. Luego, para renderizarlos, usamos la directiva Render pasando los datos necesarios. Lo mejor es que todos los Snippets dentro de un archivo comparten el mismo contexto, por lo que pueden acceder a las variables definidas en el bloque script sin necesidad de pasar props explícitas. Esto facilita mucho la organización y evita la proliferación de archivos.
El cambio más destacado y profundo de Svelte 5 es la introducción del sistema de runas, que son nuevas funciones que comienzan con $ y que permiten manejar estado, efectos y props de forma más clara y explícita. Aunque el sistema tradicional seguirá funcionando por un tiempo, las runas ofrecen una forma más moderna y parecida a la experiencia de React, pero con su propia semántica.
La runa $State reemplaza la forma tradicional de declarar variables con let para el estado interno. En lugar de eso, declaramos el estado con $State pasando el valor inicial, y obtenemos un proxy que intercepta accesos y modificaciones para actualizar el componente de forma reactiva. Por ejemplo, para crear un contador, haríamos algo así:
const count = $State(0);
function increment() {
count.value++;
}
Luego, en el template, podemos usar {count.value} para mostrar el valor y conectar el evento onClick al método increment.
La runa $Derived sirve para crear estados computados que dependen de otros estados. En lugar de actualizar manualmente valores derivados, declaramos una función que calcula el valor a partir de las dependencias, y Svelte se encarga de actualizarlo automáticamente cuando cambian esas dependencias. Por ejemplo:
const count = $State(0);
const double = $Derived(() => count.value * 2);
Cada vez que count.value cambie, double se actualizará automáticamente y el DOM se repintará con el nuevo valor.
Para quienes vienen de React, la runa $Effect será muy familiar. Permite ejecutar código cuando cambian ciertas variables de estado, sin necesidad de especificar explícitamente las dependencias, ya que el compilador detecta automáticamente qué estados se usan dentro del efecto. Además, podemos devolver una función de limpieza para cancelar intervalos, timeouts u otras suscripciones, igual que en React:
$Effect(() => {
console.log(`Count ha cambiado a ${count.value}`);
return () => {
// Código de limpieza si es necesario
};
});
Finalmente, la runa $Props introduce una forma más estructurada y clara de declarar las propiedades que recibe un componente. En lugar de usar export let, ahora podemos hacer destructuring con $Props para definir qué props son obligatorias y cuáles tienen valores por defecto. Por ejemplo:
const { requiredProp, optionalProp = 42 } = $Props;
Esto mejora la legibilidad y organización del código, dejando claro qué props espera el componente y cuáles son opcionales.
Estos son los cambios más relevantes que trae Svelte 5, que sin duda van a modificar la manera en que escribimos nuestros componentes, haciéndolos más explícitos, organizados y alineados con patrones modernos de desarrollo. Aunque habrá que acostumbrarse a dejar atrás algunas prácticas tradicionales, la evolución apunta a un código más limpio y mantenible.