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!