jotai-expert
36
总安装量
36
周安装量
#5744
全站排名
安装命令
npx skills add https://github.com/s-hiraoku/skills-factory --skill jotai-expert
Agent 安装分布
opencode
21
cursor
20
claude-code
19
codex
18
gemini-cli
16
github-copilot
16
Skill 文档
Jotai Expert
Jotai is a primitive and flexible state management library for React using an atomic approach. Always reference https://jotai.org/ for the latest API details.
Decision Tree
Need state management?
âââ Simple local state â useState (no Jotai needed)
âââ Shared state across components
â âââ Few components, same tree â Context may suffice
â âââ Many components, complex â Use Jotai â
âââ Global app state â Use Jotai â
Choosing atom type:
âââ Static value â atom(initialValue)
âââ Computed from other atoms â atom((get) => ...)
âââ Need to modify other atoms â atom(null, (get, set) => ...)
âââ Persist to storage â atomWithStorage()
âââ List of items â splitAtom() or atoms-in-atom
âââ Parameterized data â atomFamily()
Performance issue?
âââ Component re-renders too often
â âââ Only reading? â useAtomValue
â âââ Only writing? â useSetAtom
â âââ Large object? â selectAtom / focusAtom
â âââ List items? â splitAtom
âââ Async loading states â loadable() or manual loading atoms
Core Patterns
Atom Types
import { atom } from 'jotai'
// 1. Primitive: holds value
const countAtom = atom(0)
// 2. Derived read-only: computed from others
const doubleAtom = atom((get) => get(countAtom) * 2)
// 3. Derived read-write: custom setter
const celsiusAtom = atom(0)
const fahrenheitAtom = atom(
(get) => get(celsiusAtom) * 9/5 + 32,
(get, set, newF: number) => set(celsiusAtom, (newF - 32) * 5/9)
)
// 4. Write-only (action): no read value
const incrementAtom = atom(null, (get, set) => {
set(countAtom, get(countAtom) + 1)
})
Hook Selection
| Need | Hook | Re-renders on change |
|---|---|---|
| Read only | useAtomValue(atom) |
Yes |
| Write only | useSetAtom(atom) |
No |
| Both | useAtom(atom) |
Yes |
Reference Stability
// â WRONG: Creates new atom every render
function Component() {
const myAtom = atom(0) // Unstable reference
}
// â
CORRECT: Define outside component
const myAtom = atom(0)
function Component() {
const [value] = useAtom(myAtom)
}
// â
CORRECT: useMemo for dynamic atoms
function Component({ id }) {
const itemAtom = useMemo(() => atom(items[id]), [id])
}
Performance Optimization
1. Granular Subscriptions
// â BAD: Re-renders on any user field change
function UserProfile() {
const [user] = useAtom(userAtom)
return <h1>{user.name}</h1>
}
// â
GOOD: Only re-renders when name changes
import { selectAtom } from 'jotai/utils'
const nameAtom = selectAtom(userAtom, (u) => u.name)
function UserName() {
const name = useAtomValue(nameAtom)
return <h1>{name}</h1>
}
2. Efficient Lists with splitAtom
import { splitAtom } from 'jotai/utils'
const todosAtom = atom<Todo[]>([])
const todoAtomsAtom = splitAtom(todosAtom, (t) => t.id)
function TodoList() {
const [todoAtoms] = useAtom(todoAtomsAtom)
return todoAtoms.map((todoAtom) => (
<TodoItem key={todoAtom.toString()} atom={todoAtom} />
))
}
// Each item updates independently
function TodoItem({ atom }) {
const [todo, setTodo] = useAtom(atom)
// Changes here don't re-render other items
}
3. Large Objects with focusAtom
import { focusAtom } from 'jotai-optics'
const formAtom = atom({ name: '', email: '', address: { city: '' } })
// Focused atoms for each field
const nameAtom = focusAtom(formAtom, (o) => o.prop('name'))
const cityAtom = focusAtom(formAtom, (o) => o.prop('address').prop('city'))
// Each field component only re-renders when its value changes
4. Async with loadable
import { loadable } from 'jotai/utils'
const asyncDataAtom = atom(async () => fetch('/api').then(r => r.json()))
const loadableDataAtom = loadable(asyncDataAtom)
function Component() {
const data = useAtomValue(loadableDataAtom)
if (data.state === 'loading') return <Spinner />
if (data.state === 'hasError') return <Error />
return <Data value={data.data} />
}
Anti-Patterns to Avoid
- Heavy computation in components: Move to atom read functions or actions
- Creating atoms in render: Define outside or use useMemo
- Using useAtom when only reading/writing: Use useAtomValue/useSetAtom
- Over-fragmenting frequently-updated data: Batch related updates
- Nested Suspense for every async atom: Use strategic boundaries or loadable
References
Detailed documentation organized by topic:
- references/core-api.md: atom, hooks, Store, Provider API details
- references/utilities.md: atomWithStorage, loadable, splitAtom, selectAtom, atomFamily
- references/performance.md: Optimization strategies, render control, large object handling
- references/patterns.md: Organization, async patterns, testing, TypeScript, SSR, debugging
When implementing or reviewing Jotai code, load the relevant reference file for detailed guidance.