关于 jotai-expert
jotai-expert 是用于使用 Jotai 实现和审查 React 状态管理的 Skill,涵盖 Atom 与 Hook 的选择、性能模式、异步状态及常见实现误区。
主要功能
- 01Atom 类型与 Hook 选择
- 02细粒度订阅
- 03高效管理列表和对象状态
- 04使用 loadable 处理异步状态
- 05常见反模式指引
适用场景
- 01为共享 React 状态选择管理方式
- 02减少组件重新渲染
- 03管理大型表单和列表
- 04处理异步 Atom 数据
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ s-hiraoku/ skills-factory --skill jotai-expert安装后在 Claude Code 中输入/jotai-expert确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/core-api.mdpatterns.mdperformance.mdutilities.md详细介绍
Jotai 专家
Jotai 是一个采用原子化方法的 React 状态管理库,原始且灵活。请始终参考 https://jotai.org/ 获取最新的 API 详情。
决策树
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
核心模式
Atom 类型
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 选择
| 需求 | Hook | 更改时是否重新渲染 |
|---|---|---|
| 只读 | useAtomValue(atom) | 是 |
| 只写 | useSetAtom(atom) | 否 |
| 读写 | useAtom(atom) | 是 |
引用稳定性
// ❌ 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])
}
性能优化
1. 细粒度订阅
// ❌ 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. 使用 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. 使用 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. 使用 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} />
}
应避免的反模式
- 在组件中执行繁重计算:将计算移至 atom 读取函数或操作中
- 在渲染过程中创建 atom:在组件外定义,或使用 useMemo
- 只读或只写时仍使用 useAtom:改用 useAtomValue/useSetAtom
- 过度拆分频繁更新的数据:批量处理相关更新
- 为每个异步 atom 嵌套 Suspense:采用有针对性的边界或使用 loadable
参考资料
按主题整理的详细文档:
- references/core-api.md:atom、hooks、Store、Provider API 详情
- references/utilities.md:atomWithStorage、loadable、splitAtom、selectAtom、atomFamily
- references/performance.md:优化策略、渲染控制、大型对象处理
- references/patterns.md:组织方式、异步模式、测试、TypeScript、SSR、调试
实现或审查 Jotai 代码时,请加载相关参考文件以获取详细指导。
评论
支持 Markdown