DEV Community

Alex Spinov
Alex Spinov

Posted on

Jotai Has a Free Atomic State Manager That Makes React State Actually Simple

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>;
}
Enter fullscreen mode Exit fullscreen mode

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;
});
Enter fullscreen mode Exit fullscreen mode

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!
}
Enter fullscreen mode Exit fullscreen mode

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>;
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)