Atomic State: Recoil and Jotai
In this page:
What 'Atomic' State Means
Instead of one large state object (as in Redux or a single Context), atomic libraries split state into many small, independent pieces called atoms. Each atom is its own unit of state that components can read and update individually, without touching unrelated data.
Note: Think of an atom as a single useState living outside any one component, shareable by any component that imports it.
Warning: Splitting state into too many tiny atoms for tightly-related data can make keeping them in sync more work than it's worth — group closely related fields together when it makes sense.
Example: What 'Atomic' State Means
// Run in your local React project (npm install required)
// Recoil
import { atom, useRecoilState } from 'recoil';
const countAtom = atom({ key: 'count', default: 0 });
function Counter() {
const [count, setCount] = useRecoilState(countAtom);
return <button onClick={() => setCount(count + 1)}>{count}</button>;
}
⚠️ This example uses an npm package with no CDN build available here — run this in your local React project.
Recoil's RecoilRoot Requirement
Recoil needs the app wrapped in a single <RecoilRoot> component, similar to Redux's Provider or React Router's BrowserRouter, so its internal atom-tracking system can function. Without it, useRecoilState and related hooks won't work.
Note: Place <RecoilRoot> once, near the top of your app, exactly like other provider-style wrappers.
Warning: Forgetting RecoilRoot produces a runtime error the moment any component tries to use a Recoil hook.
Example: Recoil's RecoilRoot Requirement
// Run in your local React project (npm install required)
import { RecoilRoot } from 'recoil';
import App from './App';
ReactDOM.createRoot(document.getElementById('root')).render(
<RecoilRoot>
<App />
</RecoilRoot>
);
⚠️ This example uses an npm package with no CDN build available here — run this in your local React project.
Jotai: Atomic State Without a Provider
Jotai follows a similar atomic philosophy to Recoil but is designed to need no wrapping Provider at all — atoms defined with atom() can be used directly with the useAtom hook anywhere in the tree, making setup even lighter.
Note: Jotai's API (atom + useAtom) closely mirrors useState's shape, which many find intuitive coming straight from plain React.
Warning: Jotai's lack of a Provider means there's no single obvious place to reset all atoms at once (like on logout) — you handle that per-atom if needed.
Example: Jotai: Atomic State Without a Provider
// Run in your local React project (npm install required)
// Jotai — no Provider required
import { atom, useAtom } from 'jotai';
const countAtom = atom(0);
function Counter() {
const [count, setCount] = useAtom(countAtom);
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}
⚠️ This example uses an npm package with no CDN build available here — run this in your local React project.
- Creating a new atom definition inside a component's render instead of at module scope, which resets it constantly.
- Forgetting Recoil requires wrapping the app in <RecoilRoot>, similar to Redux's Provider.
- Treating atoms as if they must hold primitive values only — they can hold objects and arrays just fine.
- Atomic state management splits state into small, independent units called atoms instead of one big store.
- Recoil requires a <RecoilRoot> wrapper; Jotai does not require any wrapper at all.
- Components subscribe to individual atoms, so changing one atom only re-renders components using that specific atom.
- Both libraries are designed to feel closer to plain useState than Redux's action/reducer model.
Requires npm install recoil or npm install jotai — not available via CDN in this sandbox.
Chapter Quiz — Complete all 10 topics to unlock
0/10 topics done
Complete these topics first: