Redux has 27 files for a counter app. Zustand simplified it. Jotai made it atomic.
Jotai is a primitive and flexible state management library for React that takes an atoms-based approach — inspired by Recoil, but simpler, smaller (3.4KB), and with zero boilerplate.
The Core Idea: Atoms
import { atom, useAtom } from "jotai";
// Define an atom (like a signal/ref)
const countAtom = atom(0);
const nameAtom = atom("World");
// Use in any component — no providers needed!
function Counter() {
const [count, setCount] = useAtom(countAtom);
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}
That is it. No store. No reducers. No actions. No selectors.
Derived Atoms (Computed State)
const todosAtom = atom<Todo[]>([]);
const filterAtom = atom<"all" | "done" | "undone">("all");
// Derived atom — automatically recomputes
const filteredTodosAtom = atom((get) => {
const todos = get(todosAtom);
const filter = get(filterAtom);
if (filter === "done") return todos.filter(t => t.done);
if (filter === "undone") return todos.filter(t => !t.done);
return todos;
});
Components using filteredTodosAtom only re-render when the filtered result changes — not when unrelated todos change.
Async Atoms (Data Fetching)
const userIdAtom = atom(1);
const userAtom = atom(async (get) => {
const id = get(userIdAtom);
const res = await fetch(`/api/users/${id}`);
return res.json();
});
function UserProfile() {
const [user] = useAtom(userAtom);
return <div>{user.name}</div>; // Suspense-ready!
}
Wrap in <Suspense> and async state just works.
Write-Only Atoms (Actions)
const todosAtom = atom<Todo[]>([]);
const addTodoAtom = atom(
null, // no read
(get, set, title: string) => {
const todos = get(todosAtom);
set(todosAtom, [...todos, { title, done: false, id: Date.now() }]);
}
);
function AddTodo() {
const [, addTodo] = useAtom(addTodoAtom);
return <button onClick={() => addTodo("New task")}>Add</button>;
}
Why Jotai Over Alternatives
| Feature | Redux | Zustand | Jotai |
|---|---|---|---|
| Bundle size | 7.5KB | 1.5KB | 3.4KB |
| Boilerplate | Heavy | Light | Zero |
| Re-render optimization | Manual (selectors) | Manual (selectors) | Automatic (atomic) |
| Async support | Middleware | Middleware | Built-in |
| React Suspense | No | No | Yes |
| DevTools | Yes | Yes | Yes |
| Learning curve | Steep | Easy | Easy |
The Ecosystem
-
jotai/utils— atomWithStorage, atomWithHash, selectAtom, splitAtom -
jotai-tanstack-query— atoms powered by TanStack Query -
jotai-immer— immutable updates with Immer -
jotai-form— form state management -
jotai-devtools— browser extension for debugging
Getting Started
npm install jotai
No Provider required (optional for SSR/testing). Just import atom and useAtom.
Need help with React architecture or data-intensive applications? I build web scraping and data pipeline solutions. Email spinov001@gmail.com or check out my developer tools.
Top comments (0)