Jotai
原子化 React 状态管理库——用极简的原子模型替代 useState + useContext 组合,自底向上构建可组合、可代码分割的全局状态。
Jotai 是 React 原子化状态管理库,采用自底向上的原子模型。核心 API 极简(仅 5 个导出),支持派生状态图、Suspense、代码分割和 Provider-less 模式,gzip 后仅 4KB。2026 年与 Zustand 并列为 React 状态管理首选方案。
Jotai
原子化 React 状态管理库——用极简的原子模型替代 useState + useContext 组合,自底向上构建可组合、可代码分割的全局状态。
技术简介说明
Jotai(日语"状態"的罗马音)是由 pmndrs 维护的 React 状态管理库,由 Daishi Kato 设计。它采用原子化(Atomic)模型管理全局状态——每个状态片段(atom)是独立的、可组合的原语,组件通过订阅依赖图自动获得最小化重渲染。
与 Zustand 的"单 store 自顶向下"思路相反,Jotai 走的是"多 atom 自底向上"路线:你可以像拼乐高一样,从最基础的 atom 派生出任意复杂的状态图,而无需预先规划全局 store 结构。这使得 Jotai 既适合作为 useState 的简单升级,也能胜任企业级应用的复杂场景。
截至 2026 年 7 月,Jotai 最新版本为 v2.20.1,GitHub 星标超过 21.2k,周下载量约 530 万次,gzip 后仅 4.0 kB,是 React 生态中最轻量的状态管理方案之一。
基本信息
| 项目 | 信息 |
|---|---|
| 官网 | https://jotai.org |
| GitHub | https://github.com/pmndrs/jotai |
| npm | https://www.npmjs.com/package/jotai |
| 最新版本 | v2.20.1(2026-06-11 发布) |
| License | MIT |
| GitHub Stars | ~21.2k |
| 周下载量 | ~530 万 |
| Bundle Size | 核心 ~2 kB / 完整 ~4 kB(gzip) |
| TypeScript | 原生支持,源码 84.8% TypeScript |
| 主要维护者 | Daishi Kato(@dai_shi),同为 Zustand、Valtio、Waku 作者 |
| 所属组织 | pmndrs / jotaijs(GitHub 下有 40+ 个生态仓库) |
| Node.js 要求 | >= 18 |
| React 要求 | >= 18(支持 React 19) |
快速上手
安装
# npm
npm install jotai
# yarn
yarn add jotai
# pnpm
pnpm add jotai
# bun
bun add jotai最小示例
import { atom, useAtom } from 'jotai'
// 1. 定义 atom(全局可复用的状态原语)
const countAtom = atom(0)
const doubleAtom = atom((get) => get(countAtom) * 2) // 派生 atom
// 2. 在组件中使用
function Counter() {
const [count, setCount] = useAtom(countAtom)
const double = useAtomValue(doubleAtom)
return (
<div>
<p>Count: {count} (Double: {double})</p>
<button onClick={() => setCount((c) => c + 1)}>+1</button>
</div>
)
}完整应用配置
import { atom, useAtom, useAtomValue, useSetAtom, Provider } from 'jotai'
import { atomWithStorage } from 'jotai/utils'
// 基础 atom
const nameAtom = atom('World')
// 派生 atom(只读)
const greetingAtom = atom((get) => `Hello, ${get(nameAtom)}!`)
// 可写派生 atom
const themeAtom = atom<'light' | 'dark'>('light')
// 持久化 atom(自动同步 localStorage)
const settingsAtom = atomWithStorage('settings', {
fontSize: 14,
language: 'zh-CN',
})
// Provider 包裹(可选,不包裹时使用默认 store)
function App() {
return (
<Provider>
<Counter />
<Settings />
</Provider>
)
}
// 分别使用只读和只写 hook,优化组件粒度
function Settings() {
const greeting = useAtomValue(greetingAtom) // 只读
const setTheme = useSetAtom(themeAtom) // 只写
return (
<div>
<p>{greeting}</p>
<button onClick={() => setTheme('dark')}>暗色模式</button>
</div>
)
}核心概念与架构
原子模型(Atomic Model)
Jotai 的灵感来源于 React 的 useState,但将状态提升到了全局可共享的维度:
atom是状态的唯一原语,每个 atom 持有独立的状态值- 组件通过
useAtom订阅 atom,Jotai 根据依赖图精确判断哪些组件需要重渲染 - atom 之间可以形成派生关系(derived atoms),自动追踪依赖并级联更新
atom 依赖图示意:
countAtom ──→ doubleAtom ──→ Display 组件
│
└──→ tripleAtom ────→ Other 组件
四层架构
| 层级 | 包名 | 说明 |
|---|---|---|
| Core | jotai | 最小核心:atom、useAtom、useAtomValue、useSetAtom、Provider、createStore |
| Utilities | jotai/utils | 实用工具:持久化、SSR hydration、跨 tab 同步、加载状态等 |
| Extensions | jotai-effect、jotai-immer 等 | 官方维护的第三方库集成 |
| Tools | SWC / Babel 插件 | 编译器支持:React Fast Refresh、调试标签 |
三种 Atom 类型
// 1. 基础 atom(可读写)
const countAtom = atom(0)
// 2. 只读派生 atom
const doubleAtom = atom((get) => get(countAtom) * 2)
// 3. 可写派生 atom(自定义读写逻辑)
const doubledCountAtom = atom(
(get) => get(countAtom) * 2, // read
(get, set, newValue: number) => { // write
set(countAtom, newValue / 2)
}
)
// 4. 异步 atom(支持 React Suspense)
const fetchAtom = atom(async (get) => {
const res = await fetch(`/api/data/${get(idAtom)}`)
return res.json()
})Store 与 Provider
import { createStore } from 'jotai'
// 创建独立 store(支持多实例隔离)
const store = createStore()
// 在 React 树外读写
store.set(countAtom, 42)
const value = store.get(countAtom) // 42
// 在 React 组件树中注入
<Provider store={store}>
<App />
</Provider>核心特性
1. 极简核心 API
核心仅暴露 atom、useAtom、useAtomValue、useSetAtom、Provider 五个导出,学习曲线极低,从 useState 迁移几乎零成本。
2. 最小化重渲染(No Unnecessary Re-renders)
基于原子依赖图的精确订阅机制,组件只在依赖的 atom 值变化时重渲染,无需 useMemo、useCallback 或 React.memo 手动优化。
3. 派生状态图(Derived Atoms)
atom 可从其他 atom 派生,形成有向无环图(DAG),依赖追踪自动完成。派生 atom 可以是只读的,也可以自定义写入逻辑。
4. React Suspense 原生支持
异步 atom 可直接配合 <Suspense> 使用,Jotai 管理 Promise 的生命周期,支持 loading、error 状态的优雅处理。
5. Provider-less 模式
不提供 <Provider> 时,Jotai 自动使用内部默认 store,减少样板代码。需要多 store 隔离时再显式使用 Provider。
6. 完整的 TypeScript 支持
从核心 API 到工具函数,全部提供精确的类型推导,包括泛型 atom、可写类型推导、异步 atom 类型等。
7. 代码分割友好
每个 atom 是独立的模块,可随组件自动代码分割,无需像单 store 方案那样将全部状态打入主 bundle。
8. Store 外部访问
createStore() 允许在非 React 环境(如 Node.js、测试、定时器、Web Worker)中读写状态。
9. 丰富的工具生态
内置 atomWithStorage(localStorage/sessionStorage 持久化)、atomFamily(参数化 atom 工厂)、atomWithReducer、selectAtom 等 20+ 工具函数。
10. 官方扩展与集成
官方维护 jotai-immer(Immer 可变更新)、jotai-optics(focusAtom 聚焦派生)、jotai-effect(副作用管理)、jotai-tanstack-query(与 TanStack Query 集成)等。
生态图
Jotai 生态全景
│
├── 核心(jotai)
│ ├── atom / useAtom / useAtomValue / useSetAtom
│ ├── Provider / createStore
│ └── jotai/utils
│ ├── atomWithStorage ── localStorage / sessionStorage 持久化
│ ├── atomFamily ── 参数化 atom 工厂
│ ├── atomWithReducer ── reducer 模式 atom
│ ├── selectAtom ── 选择性订阅
│ ├── loadable ── 异步 atom 加载状态(v2.x 已废弃)
│ ├── waitForAll ── 并行等待多个 atom
│ └── hydrateAtom ── SSR hydration 支持
│
├── 官方扩展(Extensions)
│ ├── jotai-effect ── 全局副作用 / store 级别响应
│ ├── jotai-immer ── Immer 风格不可变更新
│ ├── jotai-optics ── focusAtom 结构聚焦
│ ├── jotai-tanstack-query ── TanStack Query 集成
│ ├── jotai-xstate ── XState 状态机集成
│ └── jotai-location ── URL 状态同步
│
├── 工具链(Tools)
│ ├── jotai-swc-plugin ── SWC 编译器插件(Fast Refresh)
│ └── jotai-babel-plugin ── Babel 插件(调试标签)
│
├── 社区集成
│ ├── jotai-trpc ── tRPC 集成
│ ├── jotai-form ── 表单管理
│ ├── jotai-suspensive ── Suspense 增强(@toss/suspensive)
│ └── jotai-devtools ── 浏览器开发者工具
│
└── 平台适配
├── React(Web)
├── React Native
├── Next.js / App Router
├── Remix
└── Waku
适用场景
1. useState + useContext 的性能升级
当 Prop Drilling 严重或 Context 导致不必要的全局重渲染时,Jotai 是最直接的替代方案——原子粒度订阅彻底消除 Context 的性能陷阱。
2. 需要代码分割的中大型应用
Jotai 的 atom 天然支持按模块拆分,配合动态 import() 实现状态随路由懒加载,适合代码分割需求强烈的 Next.js / Remix 项目。
3. 异步数据流与 Suspense
Jotai 的异步 atom 原生支持 React Suspense,适合需要优雅的 loading/error 状态管理的场景,如数据仪表板、内容管理系统。
4. 复杂的派生状态计算
派生 atom 形成 DAG,自动追踪依赖并缓存计算结果,适合表单联动、筛选/排序/分页组合、复杂业务规则等场景。
5. 跨组件共享的轻量状态
如主题切换、用户偏好、购物车、通知计数等——不需要 Redux 的繁重仪式,又不想引入 Context 的性能开销。
6. 需要在 React 树外管理状态
通过 createStore(),可在 Web Worker、定时器、WebSocket 回调、Node.js 脚本中直接读写状态,适合实时通信和后台任务。
7. Recoil 迁移
Meta 已停止维护 Recoil,Jotai 被社区视为事实上的替代方案——API 相近但更轻量,无字符串 key,支持 Provider-less 模式。
开发与工程化
TypeScript 配置
// Jotai 对 TypeScript 有完整的原生支持
import { atom, useAtom } from 'jotai'
// 类型自动推导
const countAtom = atom(0) // Atom<number>
const nameAtom = atom<string>('') // Atom<string>
// 派生 atom 类型推导
const doubleAtom = atom((get) => get(countAtom) * 2) // Atom<number>
// 异步 atom 类型推导
const fetchAtom = atom(async (get) => {
// 返回类型自动推导
const res = await fetch('/api/data')
return res.json() as Promise<{ id: number; name: string }>
})SSR / Next.js 集成
// app/layout.tsx(Next.js App Router)
import { Provider } from 'jotai'
import { createStore } from 'jotai'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
<Provider>
{children}
</Provider>
</body>
</html>
)
}
// 使用 atomWithStorage 实现 SSR 安全的持久化
import { atomWithStorage, createJSONStorage } from 'jotai/utils'
const safeStorage = createJSONStorage(() => sessionStorage)
const themeAtom = atomWithStorage('theme', 'light', undefined, {
getOnInit: true, // SSR 时从 storage 初始化
})测试
import { createStore } from 'jotai'
import { countAtom, doubleAtom } from './atoms'
test('count atom updates correctly', () => {
const store = createStore()
expect(store.get(countAtom)).toBe(0)
store.set(countAtom, 5)
expect(store.get(countAtom)).toBe(5)
expect(store.get(doubleAtom)).toBe(10)
})调试与 DevTools
// 安装 jotai-devtools
import { useAtomDevtools } from 'jotai/devtools'
function AtomDebugger() {
useAtomDevtools(countAtom, 'Counter')
return null
}
// SWC 插件:自动添加调试标签
// .swcrc 中配置 jotai-swc-plugin性能与安全
性能特征
| 指标 | 数据 |
|---|---|
| 核心 bundle(gzip) | ~2 kB |
| 完整包(gzip) | ~4 kB |
| 单状态更新延迟 | ~14ms(2026 基准测试) |
| 重渲染精度 | 依赖图精确订阅,零多余渲染 |
| 内存占用 | 每个 atom 仅持有当前值与订阅者列表 |
性能优化要点:
- 使用
useAtomValue+useSetAtom拆分读写,避免不必要的订阅 - 派生 atom 自动缓存,避免重复计算
selectAtom可在单个 atom 内精确订阅子字段- Provider-less 模式省去 Provider 层开销
安全考量
- XSS:Jotai 本身不处理 HTML,但持久化到
localStorage的 atom 需警惕存储型 XSS——不要存储未清洗的用户输入 - 状态注入:
atomWithStorage的getOnInit会在 SSR 时读取 storage,确保数据来自可信源 - 依赖:Jotai 核心零依赖(no dependencies),供应链风险极低
- CSP:Jotai 不使用
eval或动态代码生成,兼容严格 CSP 策略
技术对比
| 特性 | Jotai | Zustand | Redux Toolkit | Recoil | Valtio |
|---|---|---|---|---|---|
| 模型 | 原子化(多 atom) | 单 store | 单 store + slice | 原子化(多 atom) | 代理(Proxy) |
| Bundle(gzip) | ~4 kB | ~1.1 kB | ~11 kB | ~14 kB | ~3.5 kB |
| 学习曲线 | 低 | 低 | 中 | 中 | 低 |
| TypeScript | 原生优秀 | 原生优秀 | 原生优秀 | 良好 | 原生优秀 |
| 代码分割 | 天然支持 | 需配置 | 需配置 | 部分支持 | 需配置 |
| Suspense 支持 | 原生 | 需配合 | 需配合 | 原生 | 需配合 |
| DevTools | Redux DevTools / jotai-devtools | Redux DevTools | Redux DevTools | 官方 DevTools | 自带 Proxy 调试 |
| Provider 必需 | 否(可 Provider-less) | 否 | 是 | 是 | 否 |
| 派生状态 | 派生 atom(DAG) | selector | createSlice + selector | selectorFamily | Proxy 自动追踪 |
| 持久化 | atomWithStorage 内置 | persist middleware | redux-persist | 需自建 | 需自建 |
| 维护状态 | 活跃(2026 持续更新) | 活跃(2026 持续更新) | 活跃 | 已停止维护 | 活跃 |
| 适合场景 | 原子粒度、代码分割、Suspense | 轻量全局状态、快速上手 | 大型团队、复杂领域逻辑 | 已不推荐新项目使用 | 偏好可变更新风格 |
Jotai vs Zustand 核心差异
// Zustand:单 store,模块通过 selector 切片
const useStore = create((set) => ({
count: 0,
name: '',
increment: () => set((s) => ({ count: s.count + 1 })),
}))
// Jotai:多 atom,独立定义,自由组合
const countAtom = atom(0)
const nameAtom = atom('')
const incrementAtom = atom(null, (get, set) => {
set(countAtom, get(countAtom) + 1)
})- Zustand 更适合"一个全局状态对象"的心智模型,API 接近简化版 Redux
- Jotai 更适合"状态由多个独立原语组合"的心智模型,天然支持代码分割和粒度优化
- 两者均由 Daishi Kato 主导设计,哲学不同但互为补充
最佳实践
1. 用 useAtomValue + useSetAtom 替代 useAtom
// ✅ 推荐:读写分离,精确订阅
const count = useAtomValue(countAtom)
const setCount = useSetAtom(countAtom)
// ❌ 避免:不需要读写时仍使用 useAtom
const [count, setCount] = useAtom(countAtom)2. 派生 atom 优先于组件内计算
// ✅ 推荐:派生 atom 自动缓存,多组件共享
const totalAtom = atom((get) =>
get(itemsAtom).reduce((sum, item) => sum + item.price, 0)
)
// ❌ 避免:每个组件重复计算
function Total() {
const items = useAtomValue(itemsAtom)
const total = items.reduce((sum, item) => sum + item.price, 0)
// 每个订阅 items 的组件都重算
}3. 使用 atomFamily 管理参数化 atom
import { atomFamily } from 'jotai/utils'
// ✅ 缓存相同参数的 atom 实例
const userAtom = atomFamily((id: string) =>
atom(async () => {
const res = await fetch(`/api/users/${id}`)
return res.json()
})
)
function UserProfile({ id }: { id: string }) {
const user = useAtomValue(userAtom(id))
return <div>{user.name}</div>
}4. 谨慎使用 atomWithStorage
// ✅ 设置合理的初始值和存储策略
const settingsAtom = atomWithStorage(
'app-settings',
{ theme: 'light', lang: 'zh-CN' },
undefined,
{ getOnInit: true }
)
// ⚠️ 避免存储大量数据或敏感信息
// localStorage 有 5MB 限制,且可被 XSS 读取5. 多 store 隔离复杂子系统
// ✅ 不同子系统使用独立 store,避免状态耦合
const editorStore = createStore()
const viewerStore = createStore()
function EditorPanel() {
return (
<Provider store={editorStore}>
<RichTextEditor />
</Provider>
)
}技术局限与边界
已知局限
-
无内置时间旅行调试 不像 Redux 有完整的 Action 历史和时间旅行,Jotai 的 atom 更新是分散的,调试需要依赖 DevTools 扩展或手动日志。
-
大规模平坦状态需手动组织 当 atom 数量达到数百个时,需要自行规划命名和模块划分——Jotai 不提供 Redux 那样的 slice 或 domain 约定。
-
派生 DAG 的深度需谨慎 过深的派生链(>5 层)可能导致级联更新难以追踪,建议扁平化设计或使用
selectAtom截断依赖。 -
与 React 版本强耦合 Jotai 深度依赖 React 的 Concurrent Mode 和 Suspense 机制,非 React 框架(Vue、Svelte)无法使用。
-
生态规模仍小于 Redux 虽然核心 + 官方扩展已足够丰富,但社区中间件、教程、第三方集成的总量仍远不及 Redux 生态。
-
Proxy 风格更新不支持 不像 Valtio 可以直接
state.count++,Jotai 始终需要通过set函数更新,对偏好可变风格的用户不够直觉。
不适用场景
- 纯服务端状态管理——TanStack Query 更合适
- 复杂有限状态机——XState 更合适
- 跨框架共享状态——需要框架无关方案(如 Signals 或自研)
- 极简单页面——
useState足矣,引入 Jotai 反而增加复杂度
学习资源
官方资源
- Jotai 官方文档 — 最权威的入门与 API 参考
- Jotai GitHub — 源码、Issues、Discussions
- Jotai 中文文档 — 社区维护的中文翻译
- Learn Jotai(Daishi Kato 著) — 作者官方电子书
深入理解
- How Jotai Was Born — Daishi Kato — Jotai 诞生故事与设计哲学
- Behind the APIs — React Paris 2026 演讲 — Zustand/Jotai/Valtio 的创作历程
- Jotai Core Internals — 核心实现原理
- Jotai v2.20.0 Store Building Blocks — Store 构建块深度解析
社区与教程
- Jotai vs Recoil 2026 迁移指南 — Recoil 用户迁移必读
- React State Management 2026 对比 — 2026 年全景对比
- Next.js State Management: Zustand vs Jotai — Next.js 场景实战对比
- Jotai DevTools 使用指南 — 浏览器调试工具配置
2026 年现状
版本状态
截至 2026 年 7 月,Jotai 处于 v2.20.1 稳定版本,v3 尚未发布但已进入规划阶段:
- v2.20.0(2026-05)引入了 Store Building Blocks——暴露内部 API 供生态库扩展,Daishi 称其为"构建 Jotai v3 的基础"
- v2.x 最新变更中,
loadable工具已标记为废弃,为 v3 清理做准备
v3 规划方向
根据 GitHub Discussion #2889,v3 计划包括:
- 放弃旧版 TypeScript 支持(要求 TS 5.x+)
- 放弃 UMD / SystemJS 构建
- 放弃旧版 Node.js(要求 Node 20+)
package.json改为模块优先(ESM-only)- 放弃 CommonJS 构建
- 使用
process.env替代构建时常量
生态趋势
- Recoil 退役后的首选替代:Meta 已于 2024 年停止 Recoil 维护,2025–2026 年社区大规模迁移至 Jotai,Jotai 被多篇 2026 年文章称为"原子状态管理的活跃继承者"
- 与 Zustand 并列为双雄:2026 年多篇对比文章将 Zustand 和 Jotai 并列为 React 状态管理的两大首选,Redux Toolkit 退居企业级遗留项目
- pmndrs 持续投入:Jotai 与 Zustand、Valtio 同属 pmndrs 生态,共享维护资源,GitHub 组织下有 40+ 个集成仓库
- React Paris 2026 关注:Daishi Kato 在 React Paris 2026(3 月)发表主题演讲,分享三大库的设计哲学,显示社区持续活跃
- 开源健康度优秀:Jotai 与 Zustand 的 open issues 分别仅 3 个和 4 个,表明代码库稳定、维护响应迅速
总结
Jotai 在 2026 年已从一个" Recoil 的轻量替代品"成长为 React 状态管理的主流方案之一。它凭借极简 API、原子化设计、出色的 TypeScript 体验和零依赖核心,在"现代 React 状态管理"话题中与 Zustand 并列首选。随着 Recoil 退出历史舞台和 v3 的筹备,Jotai 正处于生态扩张与技术演进的关键节点。