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.md
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

PatternUse CaseDescription
Hybrid AtomReal-time dataStream + HTTP fallback
Stream AtomIPC subscriptionsonMount with subscription
Single Fetch AtomInitial dataHTTP-only async atom
Event SubscriptionIPC optimizationShared IPC listeners
Write AtomMutations (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

  1. Hybrid atom getter must NOT be async - See Why not use async
  2. No initial fetch in onMount - singleFetchAtom handles initial load
  3. Always debounce IPC handlers - prevents excessive fetches
  4. Use switch(res.status) - not res.ok
  5. Refresh read atoms after mutations -
    set(singleFetchAtom)

Detailed Documentation

Related Skills