Remix Booth
convention-driven full-stack production studio
Pro-grade state management. Zero compromises.
Rails conventions meet DJ mixing. Unmatched flexibility.
Master-level precision for your server/client state.
Pas d'encombrement, pas de surcharge, juste de la performance pure avec une empreinte minime qui ne ralentira pas votre application.
Créez un état dérivé réactif qui se met à jour automatiquement lorsque les dépendances changent, avec une prise en charge complète de TypeScript.
Suivi basé sur les signaux pour des performances optimales, mise à jour uniquement de ce qui a changé, avec suivi automatique des dépendances.
Utilisez directement les objets - pas d'actions, de reducers ou de code répétitif pour gérer votre état. Modifiez et abonnez-vous facilement.
Obtenez des instantanés d'état sérialisables à la demande avec json() - parfait pour les API, la persistance et le débogage temporel.
Inspectez votre état à tout moment, avec suivi de l'historique intégré et capacités de débogage temporel.
Simple. Réactif. Puissant.Modifiez les valeurs ci-dessous et voyez comment jods met à jour de manière réactive avec le système d'état réactif intégré
import { store, json, computed, onUpdate } from "jods";
// Create a reactive store
const user = store({
firstName: "Burt",
lastName: "Macklin",
mood: "curious"
});
// Add computed property
user.fullName = computed(() =>
`${user.firstName} ${user.lastName}`
);
// Subscribe to changes
const unsubscribe = onUpdate(user, () => {
console.log("Store updated:", user.fullName);
// Update UI or trigger other actions
});
// Get a JSON snapshot at any time 📸
console.log("📸 Snapshot:");
console.log(json(user));
JSON snapshot of your store from json(user)
. Updates automatically when values change.
Intégrez facilement jods avec React, Preact et Remix en utilisant des adaptateurs dédiés
Intégration transparente avec le cycle de vie des composants React
Intégration légère pour les applications Preact
Intégration spécialisée pour les applications Remix
import { store } from 'jods';
import { useJods } from 'jods/react';
const compteur = store({ nombre: 0 });
function Counter() {
const state = useJods(compteur);
return (
<button onClick={() => compteur.nombre++}>
Compteur: {state.nombre}
</button>
);
}
💎Couche de Données Moderne pour Remix:
réactive, typée et prête pour la persistance
État serveur et client sans hydratation manuelle
Pour des mises à jour optimistes de l'UI
Pour la validation des types à l'exécution et une excellente DX
(Prisma, MongoDB, SQLite, etc.)
Pattern uniforme dans toute votre application
// Traditional Remix Approach (without jods)
// loader.ts
export async function loader() {
const todos = await db.getTodos();
return json({ todos });
}
// action.ts
export async function action({ request }) {
const form = await request.formData();
const title = form.get("title");
await db.createTodo({ title });
return redirect("/todos");
}
// Component.tsx
function Todos() {
const { todos } = useLoaderData<typeof loader>();
return (
<div>
<h1>Todos ({todos.length})</h1>
<Form method="post">
<input name="title" placeholder="New todo..." />
<button type="submit">Add</button>
</Form>
<ul>
{todos.map(todo => (
<li key={todo.id}>
{todo.title}
{todo.completed ? " ✓" : ""}
</li>
))}
</ul>
</div>
);
}
// todos.jods.ts
import { j, defineStore } from "jods/remix";
// Define schema with Zod
const todoSchema = j.object({
id: j.string(),
title: j.string().min(1),
completed: j.boolean().default(false)
});
export const todos = defineStore({
name: "todos",
schema: j.object({
items: j.array(todoSchema)
}),
loader: async () => {
return { items: await db.getTodos() };
},
handlers: {
async addTodo({ current, form }) {
const title = form.get("title");
const newTodo = await db.createTodo({ title });
return {
...current,
items: [...current.items, newTodo]
};
}
}
});
// Export for route
export const loader = todos.loader;
export const action = todos.action;
// todos.tsx
import { todos } from "~/todos.jods";
import { useJods } from "jods/remix";
export default function TodosPage() {
// Type-safe access to your state and behavior
const { stores, actions, loaderData } = useJods(todos, "addTodo");
return (
<div>
<h1>Todos ({loaderData.items.length})</h1>
<ul>
{loaderData.items.map(todo => (
<li key={todo.id}>
{todo.title}
{todo.completed ? " ✓" : ""}
</li>
))}
</ul>
{/* Form with automatic action integration */}
<actions.addTodo.Form>
<input name="title" placeholder="New todo..." />
<button type="submit">Add</button>
</actions.addTodo.Form>
</div>
);
}
Brillance compacte — code léger aux capacités d'échelle cosmique 💠
Fonctionnalité | jods | Zustand | Redux | Preact Signals |
---|---|---|---|---|
📦 Taille du Bundle | 1 KB | 3.4 KB | 16.4 KB + Redux Toolkit | 4.2 KB |
🔗 Dépendance Framework | 🌱 None | ⚛️ React-only | 🔌 Framework-agnostic | ⚡ Preact-only |
🔑 Accès à l'État | Objet proxifié (store.foo) | Hook (useStore) | Via sélecteurs | Signal.value ou déballage JSX |
✏️ Mutations Directes | ✅ | ✅ | 👨💻 (nécessite des créateurs d'actions) | signal.value = x |
🧮 Valeurs Calculées | 🧠 via computed() | 🔧 with selector functions | 🔧 (requires selectors) | ✨ via computed() |
📸 Instantanés JSON | ✅ (built-in) | 📝 (manual) | ✅ (manual) | 📝 (manual) |
🔄 Diff Intégré | ✅ | 🤷 | 🤷 | 🤷 |
⏮️ Débogage Temporel | ✅ | ✅ | ✅ | ⏱️ |
🧠 Simplicité Conceptuelle | ✅ small mental model | ✅ (no actions/selectors) | 🧠 (complex patterns) | 🎓 (steep learning curve) |
🖥️ Intégration Serveur | 💿 Remix | 🔍 None | ✅ (manual) | 🔍 None |