Claude-skill-registry jotai-reactive-atoms
Implement reactive state management with Jotai atoms in Electron renderer. Use when creating atoms, implementing real-time updates via IPC, or setting up hybrid stream + HTTP fallback patterns. Covers event subscription optimization, debouncing, and Suspense integration.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/jotai-reactive-atoms" ~/.claude/skills/majiayu000-claude-skill-registry-jotai-reactive-atoms && rm -rf "$T"
manifest:
skills/data/jotai-reactive-atoms/SKILL.mdtags
source content
Jotai Reactive Atoms for Electron
Overview
This skill documents the Jotai atom patterns for Electron applications with IPC-based real-time updates.
Key Patterns
| Pattern | Use Case | Description |
|---|---|---|
| Hybrid Atom | Real-time data | Stream + HTTP fallback |
| Stream Atom | IPC subscriptions | onMount with subscription |
| Single Fetch Atom | Initial data | HTTP-only async atom |
| Event Subscription | IPC optimization | Shared IPC listeners |
| Write Atom | Mutations (CRUD) | Create, Update, Delete operations |
Quick Reference
Hybrid Atom Pattern
// 1. HTTP fallback (initial load) const singleFetchAtom = atomWithRefresh(async () => { const res = await client.users.$get(); return res.json(); }); // 2. Stream atom (IPC updates) - NO initial fetch const streamAtom = atom<{ value: User[] }>(); streamAtom.onMount = (set) => { const handleUpdate = debounce(async () => { const res = await client.users.$get(); if (res.ok) set({ value: await res.json() }); }, 300); return usersSource.subscribe(handleUpdate); }; // 3. Hybrid selector (exported) - NOT async export const usersAtom = atom((get) => { const stream = get(streamAtom); if (stream !== undefined) return stream.value; return get(singleFetchAtom); });
Write Atom Pattern
export const createUserAtom = atom( null, // No read value async (_get, set, data: CreateUserData) => { const res = await client.users.$post({ json: data }); switch (res.status) { case 201: { set(singleFetchAtom); // Refresh read atom return res.json(); } default: throw new Error('Failed'); } } ); // Usage: const [, createUser] = useAtom(createUserAtom);
Component Usage
const UserList = () => { const users = useAtomValue(usersAtom); const [, createUser] = useAtom(createUserAtom); // ... }; export const UsersPage = () => ( <Suspense fallback={<Loading />}> <UserList /> </Suspense> );
When to Use Each Pattern
Hybrid Atom (Stream + HTTP Fallback)
Use for data that:
- Changes frequently
- Needs real-time updates
- Is shared across components
Examples: Users, Notifications, Active Event
Stream-Only Atom
Use for data that:
- Is append-only (like logs)
- Doesn't need initial fetch
Single Fetch Atom
Use for data that:
- Rarely changes
- Doesn't need real-time updates
Key Rules
- Hybrid atom getter must NOT be async - See Why not use async
- No initial fetch in onMount - singleFetchAtom handles initial load
- Always debounce IPC handlers - prevents excessive fetches
- Use switch(res.status) - not res.ok
- Refresh read atoms after mutations -
set(singleFetchAtom)
Detailed Documentation
- HYBRID-ATOM.md - Full hybrid pattern with diagrams
- WRITE-ATOM.md - Write atom patterns (create, update, delete)
- EVENT-SUBSCRIPTION.md - IPC subscription optimization
- examples/hybrid-atom.ts - Read atom implementation
- examples/write-atom.ts - Write atom implementation
- examples/use-optimistic-value.ts - Optimistic update hook
Related Skills
- suspense-boundary-design - Suspense boundary placement and ErrorBoundary patterns