Guía de Gestión de Estados y Stores en Svelte

Los stores es la mejor opción cuando necesitas compartir y actualizar datos entre múltiples componentes. Esto se debe a que los stores permiten manejar estados globales de manera eficiente y reactiva.

¿Qué son los stores en Svelte?

Imagina un store como un contenedor que almacena un valor y notifica a los componentes que lo utilizan cuando ese valor cambia. Los stores son objetos que nos permiten gestionar el estado de nuestra aplicación de forma centralizada y reactiva.

Beneficios de usar stores en Svelte

  Beneficios

  • Estado global accesible: Permiten compartir y acceder al estado desde múltiples componentes.
  • Reactividad integrada: Los cambios en el store actualizan automáticamente todos los componentes que lo utilizan.
  • Código más limpio y modular: Facilitan la separación de la lógica de estado y reducen la duplicación de código.
  • Mayor escalabilidad: Son ideales para manejar estados complejos en aplicaciones grandes sin perder rendimiento ni claridad.

Tipos de stores en Svelte

  Stores en Svelte

  1. writable: Permite almacenar valores que pueden ser tanto leídos como modificados. Ideal para datos que cambian durante la ejecución de la aplicación.
  2. readable: Se utiliza para valores de solo lectura, aquellos que no deben ser modificados directamente desde el componente. Perfecto para datos que se obtienen de una fuente externa o calculados una sola vez.
  3. derived: Crea valores que dependen de otros stores. Su valor se recalcula automáticamente cuando los stores a los que están vinculados cambian.

1writable Store

Es el tipo de store más utilizado en Svelte. Permite tanto leer su valor actual como actualizarlo de manera reactiva.

✅ Creación de un Store Writable en Svelte

Comencemos con un ejemplo sencillo de un store writable:

js
// store.js
import { writable } from 'svelte/store';

// Creamos y exportamos un store llamado "nombre" con un valor inicial
export const nombre = writable('Urian Viera');

En este caso, hemos creado un store llamado nombre que almacena el valor inicial ‘Urian Viera’.

📌 Uso de un store en un componente

Para utilizar este store en un componente, podemos importarlo y suscribirnos a sus cambios:

js
<script>
// Importamos el store "nombre" desde el archivo store.js
import { nombre } from './store.js';
</script>

<!-- Mostramos el valor actual del store en un encabezado -->
<h1>Hola, {$nombre}!</h1>


<!-- Input vinculado al store "nombre", actualiza el valor en tiempo real -->
<input type="text" bind:value={$nombre}>

Observa cómo utilizamos el símbolo $ para acceder al valor del store dentro del componente. Este símbolo $ nos permite suscribirnos automáticamente a los cambios del store y actualizar la interfaz de usuario cuando el valor cambia.

✏️ Modificación del Valor del Store

Para modificar el valor del store, podemos utilizar los métodos set o update:

📌 Cuándo usar set(value)

set(value) se usa cuando se quiere asignar un nuevo valor directamente al store.

Ejemplo:

js
// store.js
nombre.set('Uriany');

📌 Cuándo usar update(callback)

update(callback) se usa cuando se quiere modificar el valor actual del store basándose en su estado previo.

js
// store.js

nombre.update(valorActual => valorActual + ' Brenda');

El método set asigna un nuevo valor al store, mientras que update recibe una función que toma el valor actual y devuelve el nuevo valor.

  Importante

Usa el método set() cuando quieras sobrescribir el valor del store, y update() cuando quieras modificarlo en función del valor actual.

Ejemplo: Lista de tareas

Aquí, creamos un store para manejar una lista de tareas de forma reactiva en Svelte.
Definir el store

js
// store.js
import { writable } from 'svelte/store';

// Creamos un store con un array de tareas inicial
export const tasks = writable(["Comprar pan", "Estudiar Svelte"]);

Uso de un store en un componente

Para utilizar este store en un componente, podemos importarlo y suscribirnos a sus cambios:

js
<script>
import { tasks } from './store.js'; // Importamos el store

function addTask(event) {
  if (event.key === "Enter" && event.target.value.trim() !== "") {
    // Agregamos la nueva tarea al store usando update()
    tasks.update(currentTasks => [...currentTasks, event.target.value.trim()]);
    
    event.target.value = ""; // Limpiamos el input después de agregar la tarea
  }
}
</script>

<!-- Mostramos la lista de tareas -->
<ul>
{#each $tasks as task}
  <li>{task}</li>
{/each}
</ul>

<!-- Input para agregar nuevas tareas -->
<input type="text" on:keydown={addTask} placeholder="Nueva tarea">
  Conclusión

  • Creamos el store en un archivo (store.js) para reutilizarlo en otros componentes.
  • Usamos tasks.update(), lo cual es una mejor práctica.
  • Validamos que el input no esté vacío antes de agregar la tarea.
  • event.key === "Enter": Solo agrega la tarea cuando el usuario presiona Enter.
  • trim(): Elimina espacios en blanco antes y después del texto ingresado.

🔢 Contador Reactivo con Svelte Stores

En este escenario, se crea un store writable llamado contador con un valor inicial de 0. Usa las funciones incrementar y resetear para modificar el valor del contador, y se muestra en la vista con la suscripción $contador, actualizándose al hacer clic en los botones.

js
<script>
import { writable } from 'svelte/store';

// Crear un store writable
export const contador = writable(0);

// Funciones para modificar el valor
const incrementar = () => contador.update(n => n + 1);
const resetear = () => contador.set(0);
</script>

<button on:click={incrementar}>Incrementar</button>
<button on:click={resetear}>Resetear</button>
<p>El valor actual es: {$contador}</p>

👤 Manejo de Objetos con Svelte Store

El store user mantiene un objeto con propiedades name y age. Usamos update() para modificar estas propiedades y reflejarlas en la vista con la suscripción $user.

js
<script>
import { writable } from 'svelte/store';

// Crear un writable store para un objeto
let user = writable({
  name: 'Juan',
  age: 25
});

// Función para actualizar el nombre
function updateName(newName) {
  user.update(currentUser => {
    return { ...currentUser, name: newName };
  });
}

// Función para incrementar la edad
function incrementAge() {
  user.update(currentUser => {
    return { ...currentUser, age: currentUser.age + 1 };
  });
}
</script>

<main>
<h1>Usuario: {$user.name}</h1>
<p>Edad: {$user.age}</p>
<button on:click={() => updateName('Carlos')}>Cambiar nombre a Carlos</button>
<button on:click={incrementAge}>Incrementar edad</button>
</main>

Store para Manejar el estado de un formulario

js
<!-- Form.svelte -->
<script>
import { writable } from 'svelte/store';

const name = writable('');
const email = writable('');

const submitForm = () => {
  console.log({ name: $name, email: $email });
};
</script>

<input type="text" bind:value={$name} placeholder="Nombre">
<input type="email" bind:value={$email} placeholder="Email">
<button on:click={submitForm}>Enviar</button>
  Explicación

El código usa dos stores writable para manejar el nombre y el correo, y al hacer clic en el botón, imprime los valores actuales de ambos en la consola.

2readable Store

Un store de solo lectura que puede ser configurado para actualizar su valor automáticamente.

🕒 Ejemplo de Store readable para la Hora Actual

Este código crea un store readable llamado hora que se actualiza cada segundo con la hora actual. Se muestra en la vista con $hora y se formatea usando toLocaleTimeString().

js
<script>
import { readable } from 'svelte/store';

// Crear un store readable que da la hora actual
export const hora = readable(new Date(), (set) => {
  const interval = setInterval(() => {
    set(new Date());
  }, 1000);

  return () => clearInterval(interval);
});
</script>

<p>La hora actual es: {$hora.toLocaleTimeString()}</p>

⏳ Ejemplo de Store readable con Mensaje Dinámico

Este ejemplo muestra un mensaje inicial de “Cargando…” que cambia a “¡Carga completa!” después de 3 segundos.

js
<script>
import { readable } from 'svelte/store';

// Crear un store readable que da un mensaje
export const mensaje = readable("Cargando...", (set) => {
  setTimeout(() => {
    set("¡Carga completa!");
  }, 3000);
});
</script>

<p>{$mensaje}</p>

3derived Store

Es un store que calcula su valor en función de otros stores, permitiendo que se actualice automáticamente cuando los stores de los que depende cambian.

Store con derived

Usar derived para calcular un valor en función de otro store.

js
<!-- App.svelte -->
<script>
import { writable, derived } from 'svelte/store';

// Store que contiene el precio
const price = writable(100);

// Store derivado que calcula el precio con IVA
const priceWithTax = derived(price, $price => $price * 1.21); // 21% IVA
</script>

<p>Precio original: {$price}</p>
<p>Precio con IVA: {$priceWithTax}</p>

💵 Ejemplo de Stores Derivados: Cálculo del Total

En este caso, se crea dos stores (precio y cantidad) y un store derivado total que calcula el precio total multiplicando el precio por la cantidad. Los valores de total se actualizan automáticamente cuando cambian precio o cantidad.

js
<script>
import { writable, derived } from 'svelte/store';

// Stores base
export const precio = writable(100);
export const cantidad = writable(2);

// Store derivado
export const total = derived(
  [precio, cantidad],
  ([$precio, $cantidad]) => $precio * $cantidad
);
</script>

<p>Precio: {$precio} USD</p>
<p>Cantidad: {$cantidad}</p>
<p>Total: {$total} USD</p>

🔢 Ejemplo de Store Derivado: Calcular el Doble de un Número

Aquí, secrea un store numero y un store derivado doble que calcula el doble del valor de numero. Los valores de doble se actualizan automáticamente cuando cambia numero.

js
<script>
import { writable, derived } from 'svelte/store';

// Store base
export const numero = writable(5);

// Store derivado
export const doble = derived(numero, $numero => $numero * 2);
</script>

<p>Número: {$numero}</p>
<p>Doble: {$doble}</p>

Store con update y subscribe


En Svelte, los stores proporcionan una forma reactiva de manejar datos. Puedes manipular y leer los valores de un store de manera más controlada utilizando los métodos update y subscribe.

El método update permite modificar el valor actual del store, mientras que subscribe te permite escuchar los cambios en el store y realizar acciones en consecuencia.

🔢 Ejemplo de Uso: Contador con Función de Suscripción en Svelte

js
<!-- Counter.svelte -->
<script>
import { writable } from 'svelte/store';

const count = writable(0);

// Función para incrementar el contador
const increment = () => count.update(n => n + 1);

// Función para obtener el valor manualmente
count.subscribe(value => {
  console.log('Contador actualizado: ', value);
});
</script>

<button on:click={increment}>Incrementar</button>
<p>Contador: {$count}</p>
  Explicación

El código usa un store writable para manejar un contador, incrementando su valor con la función increment. Cada vez que se actualiza el contador, se muestra el nuevo valor y se imprime en la consola.

Uso de $store para Manejar Reactividad


La sintaxis $store permite acceder al valor actual de un store de manera reactiva dentro de un componente, actualizándose automáticamente cuando el valor del store cambia.

📝 Ejemplo de Store Writable: Crear un Input Reactivo

js
<script>
import { writable } from 'svelte/store';

// Crear un store writable
const nombre = writable('Mundo');
</script>

<input bind:value={$nombre} placeholder="Escribe tu nombre" />
<p>Hola, {$nombre}!</p>

Aquí:

  • $nombre se actualiza automáticamente cuando el usuario escribe en el campo de entrada.
  • La reactividad hace que el texto del párrafo cambie dinámicamente.

🖱️ Ejemplo de Contador con Store Writable

En este escenario, el valor de contador se muestra usando $contador y se actualiza automáticamente cuando se hace clic en el botón para incrementar el valor.

js
<script>
import { writable } from 'svelte/store';

// Crear un store
export const contador = writable(0);

// Función para incrementar el contador
function incrementar() {
  contador.update(n => n + 1);
}
</script>

<p>Contador: {$contador}</p>
<button on:click={incrementar}>Incrementar</button>
  Conclusión

Los stores en Svelte son una herramienta poderosa para manejar estados de forma reactiva y compartirlos entre componentes.

  1. writable: Permite lectura y escritura del valor del store.
  2. derived: Crea un nuevo store basado en los valores de otros stores.
  3. readable: Solo lectura, se usa para datos que no deben ser modificados directamente.