Jotai原子状态
核心概念
import { atom, useAtom, useAtomValue, useSetAtom } from 'jotai'
// Primitive atom
const countAtom = atom(0)
// Derived (read-only) atom
const doubleCountAtom = atom((get) => get(countAtom) * 2)
// Read-write derived atom
const incrementAtom = atom(
(get) => get(countAtom),
(get, set, delta = 1) => set(countAtom, get(countAtom) + delta)
)
// Usage
function Counter() {
const [count, setCount] = useAtom(countAtom)
const double = useAtomValue(doubleCountAtom)
const increment = useSetAtom(incrementAtom)
return (
<div>
<p>Count: {count}, Double: {double}</p>
<button onClick={() => increment()}>+1</button>
</div>
)
}
异步Atom
import { atom } from 'jotai'
import { atomWithQuery } from 'jotai-tanstack-query'
// Async atom (Suspense-based)
const userAtom = atom(async (get) => {
const id = get(userIdAtom)
const res = await fetch(`/api/users/${id}`)
return res.json()
})
// With TanStack Query integration
const userQueryAtom = atomWithQuery((get) => ({
queryKey: ['user', get(userIdAtom)],
queryFn: () => fetchUser(get(userIdAtom)),
}))
使用atomWithStorage持久化
import { atomWithStorage } from 'jotai/utils'
// Persists to localStorage automatically
const themeAtom = atomWithStorage('theme', 'dark')
const tokenAtom = atomWithStorage('auth-token', null)
// Usage is identical to regular atom
function ThemeToggle() {
const [theme, setTheme] = useAtom(themeAtom)
return <button onClick={() => setTheme(t => t === 'dark' ? 'light' : 'dark')}>
{theme}
</button>
}
何时选择Jotai
- 需要细粒度响应性(只在特定atom变化时重渲染)
- 自下而上的状态组合(从小atom构建复杂状态)
- 基于Suspense的异步数据加载
- 避免prop drilling且不想写Context模板代码