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}>Addbutton>
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 Apph1>
<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!