☰
Jotai 深入浅出
2026/10/18 1:34:00 网站建设 项目流程

目录

  • 前言
  • 一、Jotai 概览
    • 1、Jotai 的定义
    • 2、核心概念与最小示例
  • 二、Jotai 的 API 解读
    • 1、核心 API(Jotai 的最基础能力)
      • (1)、atom() —— 创建一个最小可独立更新的状态单元
      • (2)、useAtom() —— 读写 atom 的主要方式
      • (3)、useAtomValue()、useSetAtom()(解耦读写)
        • ①、useAtomValue(atom)
        • ②、useSetAtom(atom)
      • (4)、Provider —— 提供一个独立的 Atom Store
    • 2、原子增强 API(给 atom 加能力)
      • (1)、atomWithDefault(initializer)
      • (2)、atomWithReducer(atom, reducer)
      • (3)、atomWithStorage(key, initialValue)
      • (4)、atomWithReset(initialValue)
    • 3、派生(computed)与异步 API
      • (1)、派生 atom(读函数)
      • (2)、可写派生 atom(读函数 + 写函数)
      • (3)、异步 atom(async)
      • (4)、异步可写原子(异步 action)
    • 4、Store 级 API(高级)
      • (1)、createStore() —— 手动创建独立 store
      • (2)、useStore()
    • 5、开发者工具 API
      • (1)、atom.onMount(set => ...) —— 原子的生命周期
      • (2)、useAtomCallback()(在回调中读取/写入 atom)
  • 三、Jotai 的思维模式总结(重要 ⭐️)
  • 四、性能细节与最佳实践
  • 五、TypeScript 使用技巧(类型安全)
  • 六、扩展中间件与生态(常见插件)
  • 七、SSR(服务端渲染)与 hydration
  • 八、Persist(本地持久化)
  • 九、并发、Suspense 与错误边界(React 18/19)
  • 十、测试策略
  • 十一、高级技巧与模式
      • (1)、表单模式(local draft + submit)
      • (2)、Optimistic update(乐观更新)
      • (3)、Derived cache(缓存派生)
      • (4)、atom factories + dependency injection
  • 十二、与其它状态库的对比(选择建议)
  • 十三、常见问题
  • 十四、16. 进阶:atomic design 与模块化架构示例(企业级)

前言

Jotai 官方文档

Jotai 的核心设计深度绑定 React 的 Hooks 机制和其调度器(Scheduler)。它的“原子”概念、读写操作以及衍生状态的计算,都是围绕 React 的渲染生命周期和 Hooks 规则构建的。将其移植到 Vue,几乎相当于重写整个库,而不是简单地做一个适配层。因此,目前没有成熟、官方的 Vue 版本。

特性ZustandJotai
设计哲学集中式、自上而下。基于单一、集中的Store组织状态和逻辑。原子化、自下而上。将状态分解为最小独立单元(Atom),可自由组合。
心智模型类似“全局可观测的对象”,适合有组织、模块化的应用状态。类似“React自己的useState,但可全局共享”,更贴近组件化思维。
核心优势极简API、开箱即用的状态切片与优化、易于在React外部使用。极致的细粒度响应性、自动计算派生状态。
性能特点通过选择器实现精准订阅,避免不必要的重渲染。原子级的依赖追踪,确保只重渲染真正相关的组件。
最佳适用场景大多数具有明确模块边界的中大型应用(如后台管理、电商平台)、需要从Redux迁移的场景。状态高度分散、依赖关系复杂(如复杂表单、富文本编辑器)、UI变化频繁的应用。
不适合的场景状态极度分散、快速变化的UI场景。需要高度中心化、强约束状态流转模式的应用。

在未来的 React 生态里,Zustand 和 Jotai 很可能会长期共存,甚至在同一项目中互补使用。
例如:

  • 用 Zustand 管理核心业务模块的共享状态
  • 用 Jotai 处理 UI 交互、表单等局部复杂状态

一、Jotai 概览

1、Jotai 的定义

Jotai(日文“原子”的意思)是一个基于原子(atom)模型的 React 状态管理库,主张最小 API、按需订阅、可组合的原子与派生(derived)状态。

核心卖点:

  • 极简 API:atom、useAtom、Provider 就能做大多数事。
  • 按需订阅:组件只会因为它依赖的 atom 变更而渲染。
  • 可组合性:派生 atom 很容易组合、复用。
  • 与 React Hooks 自然契合:原生 Hook 使用体验。
  • 生态:有 jotai/utils、jotai/immer、jotai/devtools、jotai/query 等扩展。

适合场景:中大型应用的局部/全局状态管理、微状态组合、对细粒度重渲染有高要求的 UI 场景、逐步从 Context/Redux 迁移的项目。

2、核心概念与最小示例

import{atom,useAtom}from'jotai';// 定义原子(最小状态单元)constcountAtom=atom(0);// 在组件中读取与写入functionCounter(){const[count,setCount]=useAtom(countAtom);return<button onClick={()=>setCount(c=>c+1)}>{count}</button>;}

关键点:

  • atom(initial):创建可读写 atom(也可以创建只读 atom)。
  • useAtom(atom):返回 [value, setValue]。组件只订阅它使用的 atom。
  • atom 是可组合、可传入参数(通过工厂模式或 atomFamily 实现)的。

二、Jotai 的 API 解读

1、核心 API(Jotai 的最基础能力)

(1)、atom() —— 创建一个最小可独立更新的状态单元

constcountAtom=atom(0)

原子是什么?

  • Jotai 的最核心抽象:可订阅、可更新的状态。
  • 类似 Redux 的 store 片段,但 天然支持细粒度渲染。
  • 每个 Atom 自动支持订阅,不需要 selector。
形式说明
atom(value)原子存普通值
atom(get => ..., (get, set, update) => ...)派生/可写原子

(2)、useAtom() —— 读写 atom 的主要方式

const[count,setCount]=useAtom(countAtom)
  • 自动订阅 atom
  • Atom 更新后只使使用它的组件重渲染(细粒度)

关键:为什么 Jotai 更新只重渲染使用 atom 的组件?

因为原子本身是订阅对象,组件只订阅它依赖的 atom,不会像 Redux Provider 那样全局 root 订阅。

(3)、useAtomValue()、useSetAtom()(解耦读写)

①、useAtomValue(atom)

只读:

constcount=useAtomValue(countAtom)
②、useSetAtom(atom)

只写:

constsetCount=useSetAtom(countAtom)

解耦后可以避免多余渲染、减少 props 传递。

(4)、Provider —— 提供一个独立的 Atom Store

<Provider><App/></Provider>

在 Jotai 中,Provider 就是一个“状态容器”。

特点:

  • 你可以创建多个 Provider(与 Redux 必须单例不同)
  • 每个 Provider 内的 atom 状态互不影响
  • 支持多窗口、嵌套组件、可重置的状态域

2、原子增强 API(给 atom 加能力)

(1)、atomWithDefault(initializer)

动态默认值(初次 get 才计算)

constcountAtom=atomWithDefault((get)=>get(baseAtom)*2)

适用:

  • 惰性计算
  • 依赖其他 atom 的默认值
  • 延迟初始化(如 localStorage)

(2)、atomWithReducer(atom, reducer)

Redux-style reducer 写法:

constcountAtom=atom(0)constreducerAtom=atomWithReducer(countAtom,(state,action)=>{if(action==='inc')returnstate+1returnstate})

你甚至可以把 Redux reducer 拿来直接复用。

(3)、atomWithStorage(key, initialValue)

自动同步 localStorage / sessionStorage

constthemeAtom=atomWithStorage('theme','light')

Jotai 对持久化做得非常优雅:

  • 自动同步多 tab
  • 支持自定义 storage adapter

(4)、atomWithReset(initialValue)

带 reset 功能的 atom:

constcountAtom=atomWithReset(0)constsetCount=useSetAtom(countAtom)setCount(RESET)// 重置为 0

与业务里的“一键清空表单”“退出登录”特别适配。

3、派生(computed)与异步 API

(1)、派生 atom(读函数)

constdoubleCountAtom=atom((get)=>get(countAtom)*2)

派生 atom 的特点:

  • 任何 atom 改变自动重新计算
  • 计算值自动 memo
  • 不需要 useMemo / selector

(2)、可写派生 atom(读函数 + 写函数)

constcountAtom=atom(0)constdoubleCountAtom=atom(get=>get(countAtom)*2,(get,set,newValue)=>set(countAtom,newValue/2))

这是 Jotai 的“神技”,使得:

  • 任何派生 atom 都能变成“可写的 computed”
  • 非常适合 form 场景

(3)、异步 atom(async)

constuserAtom=atom(async(get)=>{constres=awaitfetch('/api/user')returnres.json()})

优点:

  • 原生支持 Suspense
  • 依赖变化自动重新触发请求
  • 不需要 useEffect

这是与 Redux、Recoil、Zustand 最大的差异。

(4)、异步可写原子(异步 action)

constsaveUserAtom=atom(null,async(get,set,user)=>{awaitfetch('/api/save',{method:'POST',body:JSON.stringify(user)})set(userAtom,user)})

你可以在 atom 写函数做:

  • 请求
  • 延迟
  • 批处理
  • 事务

Jotai 允许你把业务逻辑包成可组合的 atom,不需要额外 action 层。

4、Store 级 API(高级)

(1)、createStore() —— 手动创建独立 store

conststore=createStore()store.get(countAtom)store.set(countAtom,1)

用途:

  • 在 React 外使用 Jotai(比如 WebWorker、Service、RPC)
  • 集成到微前端
  • 单元测试
  • 时光旅行

(2)、useStore()

暴露内部 store 实例:

conststore=useStore()store.sub(countAtom,()=>console.log('changed'))

可用于监听 atom 变化(非常底层)。

5、开发者工具 API

(1)、atom.onMount(set => …) —— 原子的生命周期

当某个 atom 第一次被组件订阅时触发:

constcountAtom=atom(0)countAtom.onMount=(set)=>{constinterval=setInterval(()=>set(c=>c+1),1000)return()=>clearInterval(interval)}

这几乎等同于组件级 useEffect,但绑定在 atom 上,而不是组件上。

用于:

  • 轮询
  • WebSocket
  • 实时数据同步

优化:不被订阅就不执行任务

(2)、useAtomCallback()(在回调中读取/写入 atom)

constcallback=useAtomCallback(useCallback(async(get,set)=>{constuser=get(userAtom)set(logAtom,`Fetched:${user.name}`)},[]))

为什么它存在?

  • 因为 React 回调里不能直接调用 useAtom(),这是 Jotai 的解决方案。

三、Jotai 的思维模式总结(重要 ⭐️)

React 官方精神:小而可组合(small & composable)。

Jotai 把状态拆成最小粒度的原子:

  • 每个 atom 就像函数式编程的值容器
  • 你可以对 atom 做映射、聚合、派生、链接、组合
  • 组件只订阅自己需要的 atom,极致性能

相比:

状态库设计理念
Redux单一全局 store + reducer/action
MobX面向对象的响应式模型
Zustand一个大对象 + selector
Recoil类似,但更激进(Jotai 更纯粹)
Jotai仅由 atom 组成,可以任意组合、派生

四、性能细节与最佳实践

  • 选择器式订阅:确保组件只订阅需要的 atom(不要在组件里 useAtom 返回一个新对象)。
  • 避免在 atom 的 read 中做昂贵同步计算:read 在每次依赖改变时会运行;把重计算缓存到 atom 内或使用 useMemo 在组件侧。
  • 拆分大状态:使用实体 map 而不是巨对象或大数组。
  • 使用 Provider 的 scope:在大型应用或微前端中使用多个 scope 隔离 store,避免跨域影响。
  • 批量更新:write 函数里可以一次性 set 多个 atom,避免多次触发渲染。

五、TypeScript 使用技巧(类型安全)

type User={id:string;name:string};constuserAtom=atom<User|null>(null);constuserNameAtom=atom((get)=>get(userAtom)?.name??'');
  • 给 atom(initial) 明确类型可以让 useAtom 返回带类型推断的值/写入函数。
  • 对于带 write 的 atom,atom<Read, Write> 的写法并不需要显式类型,只要初始类型明确即可。

六、扩展中间件与生态(常见插件)

  • jotai/utils:提供 atomFamily, atomWithStorage, atomWithSubscription, atomWithReducer 等实用工厂。
  • jotai/immer:在 atom 的 write 中使用 immer 风格的可变写法,代码更简洁。
  • jotai/devtools:连接 Redux DevTools,便于调试(注意仅开发环境)。
  • jotai/query:与 TanStack Query 的集成,提供 atomWithQuery,把缓存/预取能力补到 atom 层。
  • jotai/react(核心):提供 Provider, useAtom, useAtomValue, useSetAtom 等 hooks。

七、SSR(服务端渲染)与 hydration

Jotai 支持 SSR,但需要手动序列化/初始化 atom state ——流程(常见做法):

  • 在服务器端创建 atom state、执行所有需要的异步 atom(或通过 renderToStringWithData)。
  • 序列化初始 atom 状态为 JSON,放入 HTML。
  • 客户端在创建 Provider 时把初始 state 注入(getDefaultStore / Provider initialValues 的方式)。

示例概念:

// server: render -> collect atom values -> window.__JOTAI_PRELOAD__ = {...}// client:constinitial=window.__JOTAI_PRELOAD__;constProvider=createProviderWithInitial(initial);

具体实现可参考官方 SSR 示例或社区库(注意 hydration 时避免重复执行副作用)。

八、Persist(本地持久化)

常见做法:

  • 使用 atomWithStorage(jotai/utils)实现 localStorage/sessionStorage 持久化。
  • 对复杂结构使用 partialize(只存必要字段)并制定 migrate 逻辑,防止版本变更导致数据不兼容。

示例:

import{atomWithStorage}from'jotai/utils';constauthAtom=atomWithStorage('auth',{token:null});

九、并发、Suspense 与错误边界(React 18/19)

  • Suspense:Jotai 的异步 atom 与 Suspense 自然配合,返回 Promise 的 read 会抛出 Promise。
  • Error boundary:异步 atom 的错误会被 ErrorBoundary 捕获(同 React 约定)。
  • useAtomValue / useSetAtom:在并发更新中用 useSetAtom 只获取 setter,有助于避免闭包 stale 问题。

十、测试策略

  • 单元测试:独立测试 atom read/write 行为,使用 getDefaultStore(或不使用 Provider 的情况下直接调用 atom 的 get)。
  • 组件测试:在 Jest + React Testing Library 中 wrap 组件的 render 时传入 Provider 并可注入初始 atom 状态。
  • 重置 store:在每个测试用例后清理 atom 状态(避免测试间污染)。

十一、高级技巧与模式

(1)、表单模式(local draft + submit)

  • 把表单草稿放在临时 atom(局部),提交时把值写入 server-atom 或触发 action/side-effect。
  • Benefit:避免频繁写入全局 state 或 network。

(2)、Optimistic update(乐观更新)

  • 在 write 中先更新本地 atom,然后发请求,失败则回滚(在 atom write 中管理回滚快照)。

(3)、Derived cache(缓存派生)

  • 对昂贵计算的派生,缓存结果在 atom 中并提供 TTL 或依赖 invalidation(通过另一个 atom 触发刷新)。

(4)、atom factories + dependency injection

  • 对于可复用模块(比如 chart store),用工厂创建带入依赖(如 API 客户端)更易测试。

十二、与其它状态库的对比(选择建议)

需求JotaiZustandRedux ToolkitRecoil
API 简洁度⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
细粒度订阅⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
大型可维护性⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
SSR 支持⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
学习曲线低低高中
生态 & 工具中中最强小众

实务建议:

  • 想要最小学习成本且需要按组件订阅:Jotai 很合适。
  • 需要严格架构、Timeline、复杂中间件:Redux Toolkit 更稳。
  • 需要极简 local store + tiny bundle:Zustand 很好。

十三、常见问题

  • 把整个应用状态放到一个大 atom:导致所有组件频繁重渲染。
  • Selector 返回新对象:在 read 中返回新对象会导致订阅组件无谓更新。
  • 在 atom read 中做副作用:read 应保持纯计算;副作用放到 write 或 useEffect 中。
  • 滥用 Suspense:没有正确错误边界会导致用户体验不佳。
  • 不处理持久化迁移:localStorage schema 改变必需 migration。

十四、16. 进阶:atomic design 与模块化架构示例(企业级)

项目结构建议:

src/atoms/auth/atoms.ts hooks.ts todo/atoms.ts selectors.ts features/TodoList.tsx TodoItem.tsx pages/providers/JotaiProvider.tsx// 用于 scope / SSR hydration

示例 auth/atoms.ts:

exportconsttokenAtom=atomWithStorage('token',null);exportconstuserAtom=atom(async(get)=>{consttoken=get(tokenAtom);if(!token)returnnull;constres=awaitfetch('/api/me',{headers:{Authorization:token}});returnres.json();});

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询