State management in React can sometimes feel like overkill. Whether you're reaching for Redux, Zustand, or Jotai, you might be introducing complexity when all you need is a minimal way to share state globally across components.
That’s where @odemian/react-store
shines — a tiny, typed, selector-based, and dependency-free global state library powered by useSyncExternalStore
.
In this article, we’ll walk through how to build a clean, performant Todo App using @odemian/react-store
in just a few minutes.
🔧 Installation
npm install @odemian/react-store
🏗️ Step 1: Set up the Todo Store
Create a new file called stores/todoStore.ts
:
import { createStore } from "@odemian/react-store"; export type TTodo = { id: number; name: string; done: boolean; }; // Initialize the store with one task export const [useTodos, updateTodos] = createStore<TTodo[]>([ { id: Date.now(), name: "First task", done: false }, ]); // Add a new todo export const addTodo = (name: string) => updateTodos((todos) => [ ...todos, { id: Date.now(), name, done: false }, ]); // Toggle todo status export const toggleTodo = (id: number) => updateTodos((todos) => todos.map((t) => (t.id === id ? { ...t, done: !t.done } : t)) ); // Remove a todo export const removeTodo = (id: number) => updateTodos((todos) => todos.filter((t) => t.id !== id));
🧑🎨 Step 2: Create Todo Input Component
import { useState } from "react"; import { addTodo } from "./stores/todoStore"; const CreateTodo = () => { const [text, setText] = useState(""); const onAdd = () => { if (!text.trim()) return; addTodo(text); setText(""); }; return ( <div> <input value={text} onChange={(e) => setText(e.currentTarget.value)} onKeyDown={(e) => e.key === "Enter" && onAdd()} placeholder="Add new task..." /> <button onClick={onAdd}>Add</button> </div> ); }; export default CreateTodo;
📋 Step 3: Display and Interact with Todos
import { useTodos, toggleTodo, removeTodo } from "./stores/todoStore"; const TodoList = () => { const todos = useTodos(); // Full state read return ( <ul> {todos.map((todo) => ( <li key={todo.id}> <label> <input type="checkbox" checked={todo.done} onChange={() => toggleTodo(todo.id)} /> {todo.name} </label> <button onClick={() => removeTodo(todo.id)}>❌</button> </li> ))} </ul> ); }; export default TodoList;
🧩 Step 4: Combine Components in App
import CreateTodo from "./CreateTodo"; import TodoList from "./TodoList"; const App = () => ( <main> <h1>📝 Todo App</h1> <CreateTodo /> <TodoList /> </main> ); export default App;
✅ Why @odemian/react-store
?
- Tiny
- Fast: Uses
useSyncExternalStore
for optimal React updates - Typed: Works seamlessly with TypeScript
- Selector-based: Components only re-render when selected state changes
- No boilerplate: No Provider, context, or hook destructurings in each component
🧾 Summary
With @odemian/react-store
, global state is no longer complex. You get the power of selector-based subscriptions, type safety, and zero dependencies — all in a micro-package perfect for small to medium React apps.
If you’re tired of bloated state management tools and just want something clean, predictable, and fast, give it a try! 🚀
💬 Have questions or want to see more patterns with react-store
? Drop them in the comments!
Top comments (0)