Documentación
Yoltra con Next.js
Yoltra funciona muy bien en Next.js, como estado del lado del cliente. Esta guía cubre ambos routers y los dos patrones que mantienen seguro el renderizado en servidor.
#Alcance: Yoltra es estado de cliente
Yoltra es un contenedor de estado del lado del cliente: reactividad de grano
fino, un log de eventos y DevTools con time-travel para UIs interactivas. El
renderizado en servidor (SSR) y los React Server Components están fuera de
alcance por diseño, el estado de Yoltra vive y muta en el navegador. Eso no es
una carencia; es el nicho. Trae y renderiza tus datos iniciales con las
herramientas de Next (Server Components, getServerSideProps, route handlers), y
usa Yoltra para el estado interactivo de cliente encima.
En la práctica, eso significa que los hooks de Yoltra corren en Client
Components ("use client" en el App Router; en el Pages Router cada componente
ya lo es).
#Pages Router (el ejemplo incluido)
El ejemplo yoltra-in-nextjs (▶ Abrir la demo en vivo) usa el Pages
Router, donde cada componente es un Client Component, así que el modelo "sin
provider" de createYoltra simplemente funciona.
// state/yoltra.ts, creado una vez, los hooks usan este store
import { createYoltra } from "@yoltra/react";
export const { useAtomicProp, useEmit } = createYoltra({
name: "App",
reducer: { theme: themeReducer },
});// components/ThemeToggle.tsx, sin Provider
import { useAtomicProp, useEmit } from "@/state/yoltra";
export function ThemeToggle() {
const theme = useAtomicProp({ reducer: "theme", property: "mode" });
const emit = useEmit();
return <button onClick={() => emit("theme", "toggle", null)}>{theme}</button>;
}Envuelve con <StoreProvider> en _app.tsx solo si quieres acotar una instancia
específica del store; si no, el default del módulo está bien.
#App Router
Los componentes del App Router son Server Components por defecto, y los hooks
de Yoltra son solo de cliente. Pon el store y los componentes que lo leen detrás
de "use client".
#Patrón A, singleton de cliente simple
Para un store puramente de cliente (inicializado en el navegador, no desde datos del servidor), un store a nivel de módulo está bien:
// state/yoltra.ts
"use client";
import { createYoltra } from "@yoltra/react";
export const { useAtomicProp, useEmit } = createYoltra({
name: "App",
reducer: { cart: cartReducer },
});// components/Cart.tsx
"use client";
import { useAtomicProp, useEmit } from "@/state/yoltra";
export function Cart() {
const count = useAtomicProp({ reducer: "cart", property: "items" }, (items) => items.length);
// …
}#Patrón B, aislamiento por request (recomendado para SSR)
Un store a nivel de módulo se evalúa una vez por proceso de servidor, así que se compartiría entre requests durante SSR, el estado de un usuario podría filtrarse al de otro. Si tus componentes renderizan en el servidor, crea el store por render dentro de un provider de cliente:
// state/StoreProvider.tsx
"use client";
import { useState, type ReactNode } from "react";
import { StoreProvider as YoltraProvider } from "@/state/yoltra";
import { makeStore } from "@/state/makeStore";
export function AppStoreProvider({ children }: { children: ReactNode }) {
// Un store nuevo por render de cliente, nunca compartido entre requests.
const [store] = useState(() => makeStore());
return <YoltraProvider store={store}>{children}</YoltraProvider>;
}// app/layout.tsx (Server Component), monta el provider de cliente una vez
import { AppStoreProvider } from "@/state/StoreProvider";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html><body><AppStoreProvider>{children}</AppStoreProvider></body></html>
);
}Donde makeStore() devuelve createStore({...}) con tus reducers. Los hooks de
createYoltra prefieren el store provisto vía StoreProvider, así que todos los
componentes de cliente debajo del provider comparten esa instancia por request.
#DevTools en Next.js
withDevtools usa el WebSocket del navegador, que no existe durante el
renderizado en servidor, protégelo para que solo corra en el navegador:
import { withDevtools } from "@yoltra/devtools-browser-agent";
if (typeof window !== "undefined") {
withDevtools(store, { port: 9800, allowReplay: true });
}Inicia el hub (npx @yoltra/devtools-server --port 9800) y abre el panel de la
extensión, ver los pasos de configuración local
una vez instalada la extensión.
#Checklist
- Los hooks de Yoltra viven en Client Components (
"use client"en App Router). - Para SSR, crea el store por request (Patrón B), no a nivel de módulo.
- Protege
withDevtoolscontypeof window !== "undefined". - Trae los datos iniciales/de servidor con las herramientas de Next; hidrátalos
en el store en el cliente (p. ej. emite un evento
initen un effect o al montar).
#Siguientes pasos
- Guía de Migración · Guía de Testing
- Ejemplo de Next.js, Pages Router + cambio de tema · ▶ Abrir la demo en vivo
- API de @yoltra/react