Astro nanostores

Cómo estructurar el estado global de aplicaciones Astro con nanostores.

astro-nanostores

Como ya hemos visto Astro prioriza el HTML estático y sólo carga el JavaScript necesario. Sin embargo, cuando llega el momento de compartir estado entre componentes Astro, necesitamos una solución que siga con la filosofía del framework. Ahí es donde Nanostores puede ser una buena opción.

Nanostores es una biblioteca pequeña para gestionar estado reactivo. Su tamaño reducido, su compatibilidad con múltiples entornos (incluyendo el lado del cliente en Astro) y su API nos permiten mantener el control del estado.

¿Por qué usar Nanostores en Astro?

Astro separa claramente el renderizado en el servidor del comportamiento en el cliente. Nanostores puede integrarse dentro de esta arquitectura, sin interferir con la naturaleza del rendering híbrido de Astro.

Las razones principales para considerarlo:

  • No requiere configuración para empezar.
  • Compatible con React, Vue, Svelte, Solid y otros frameworks soportados por Astro Islands.
  • Tiene una API pequeña y predecible.
  • Permite persistencia, sincronización con localStorage y uso de derivados (computed) de forma sencilla.

Instalación

Primero, lo añadimos al proyecto:

Terminal
npm install nanostores

Definir un store

Vamos a crear un ejemplo con un store simple para gestionar la variable de un tema claro/oscuro:

src/stores/theme.js
import { atom } from 'nanostores'
export const theme = atom('light')
export function toggleTheme() {
theme.set(theme.get() === 'light' ? 'dark' : 'light')
}

Como ves es muy intuitivo, guardamos el valor por defecto en un atom() y podemos usar set y get para manejar el valor.

Usar el store en un componente React (Astro Island)

La librería también tiene unos adaptadores para otros frameworks como React, podemos usarlo de la siguiente manera:

src/components/ThemeToggle.jsx
import { useStore } from '@nanostores/react'
import { theme, toggleTheme } from '../stores/theme'
export default function ThemeToggle() {
const $theme = useStore(theme)
return (
<button onClick={toggleTheme}>
Tema actual: {$theme}
</button>
)
}

Y en el archivo .astro:

---
import ThemeToggle from '../components/ThemeToggle.jsx'
---
<ThemeToggle client:load />

Gracias al client:load, el componente se hidrata en el navegador y puede interactuar con el store.

Persistencia con localStorage

Podemos mantener el valor entre sesiones usando el plugin persistent:

src/stores/theme.js
import { persistentAtom } from '@nanostores/persistent'
export const theme = persistentAtom('theme', 'light', {
encode: JSON.stringify,
decode: JSON.parse,
})

Esta función guarda el valor cada vez que cambia y lo restaura al recargar desde el Localstorage.

Derivar valores

También podemos derivar nuevos valores con computed:

import { computed } from 'nanostores'
import { theme } from './theme'
export const isDark = computed(theme, (value) => value === 'dark')

Esto es útil para condicionar clases, estilos u otros efectos secundarios.

Consideraciones

Es importante recordar que, en Astro, el estado en el servidor y el cliente no es compartido automáticamente. Las Nanostores deben usarse en componentes que se ejecutan en el navegador. Si necesitamos pasar datos del servidor al cliente, debemos hacerlo explícitamente vía props o serialización.

Nanostores no reemplaza otras soluciones si estamos construyendo una SPA compleja o si necesitamos un sistema de sincronización avanzado entre pestañas o sockets. Pero para proyectos que priorizan simplicidad, velocidad de carga y claridad, encaja bastante bien.

Conclusión

Incorporar Nanostores en Astro nos permite trabajar con el estado global. La integración con Astro Islands y su enfoque progresivo nos ayuda a mantener el control en cada parte del proyecto.

Podemos empezar con un store, escalar gradualmente si hace falta y mantener el enfoque modular que Astro promueve.