Why Jotai?
Jotai takes a different approach than Redux or Zustand. Instead of one large global store (Top-Down), you build your state from small, independent pieces called atoms (Bottom-Up) and combine them to form your application state.
- Atomic Model: State is fragmented into "atoms". Components subscribe only to the specific atoms they use, ensuring that updates to one part of the app never cause re-renders in unrelated parts.
- Derived State: You can easily create atoms that compute their value based on other atoms. If the dependency changes, the derived atom updates automatically.
- Suspense Support: Jotai treats async data like any other atom. It has first-class support for React Suspense, allowing you to handle loading states declaratively.
- No Keys Required: Unlike Recoil, Jotai relies on object reference identity for atoms, so you don't need to manually provide unique string keys for every atom.
- TypeScript Native: It is written in TypeScript and offers excellent type inference without complex generic gymnastics.
Code Snippet
In Jotai, state is defined outside the component tree, but consumed like useState.
import { atom, useAtom } from 'jotai'
// 1. Define primitive atoms
const priceAtom = atom(10)
const quantityAtom = atom(2)
// 2. Define derived atoms (Computed values)
// This atom is read-only and updates whenever price or quantity changes
const totalAtom = atom((get) => get(priceAtom) * get(quantityAtom))
function Cart() {
// 3. Consume atoms
const [price, setPrice] = useAtom(priceAtom)
const [total] = useAtom(totalAtom)
return (
<div>
<input
type="number"
value={price}
onChange={(e) => setPrice(Number(e.target.value))}
/>
<p>Total: ${total}</p>
</div>
)
}
In this example, totalAtom is reactive. You never strictly "set" the total; it is always a reflection of its dependencies.
Pros and Cons
No library is perfect; understanding the trade-offs is key to selecting the right tool.
Pros
- Granular Performance: It virtually eliminates the need for
React.memooruseMemofor state selection performance optimizations. - Composition: Building complex logic by composing small atoms feels very natural and "React-like".
- Bundle Size: It is significantly smaller than Redux Toolkit or Recoil, making it ideal for performance-critical applications.
Cons
- Visualization: Unlike Redux's single state tree, Jotai's state is scattered across many atoms. Visualizing the entire app state or debugging a dependency chain can be difficult.
- Circular Dependencies: It is possible to accidentally create loops where Atom A depends on Atom B, which depends on Atom A, causing runtime errors.
- Mental Model Shift: Developers coming from Redux might struggle with the lack of a central "dispatcher" and the decentralized nature of logic.
Comparison with Other State Management Libraries
The table below outlines the positioning differences between Jotai and other popular state management libraries to help you make an informed decision:
| Library | Design Philosophy | Best For | Pain Points |
|---|---|---|---|
| Jotai | Atomic Decentralized, bottom-up composition of state pieces. | Highly Interactive UIs Dashboards, canvas editors, and apps with complex derived state. | Debugging Harder to see the "big picture" of the app state at a glance. |
| Zustand | Simplified Flux Centralized store with hook-based access. | General Application State User sessions, settings, and standard CRUD data. | Derived State Less declarative than Jotai for complex computed values. |
| Recoil | Atomic The original atomic library from Meta. | Legacy Projects Existing Recoil codebases (Jotai is generally preferred for new apps). | Maintenance Development has slowed significantly; bundle size is large. |
Ecosystem & Extensions
Jotai provides a rich set of utilities in separate packages or standard bundles to handle common scenarios:
atomWithStorage: Automatically persists the atom's value tolocalStorageorsessionStorage.jotai-tanstack-query: A seamless integration with TanStack Query, allowing you to use queries as atoms.jotai-location: Syncs an atom's state with the URL hash or query parameters.