Terminal.skills
Skills/jotai
>

jotai

Manage React state with Jotai atoms. Use when a user asks to manage granular React state, replace Context with something performant, create derived state, or build bottom-up state management with atomic primitives.

#jotai#react#state#atoms#frontend
terminal-skillsv1.0.0
Works with:claude-codeopenai-codexgemini-clicursor
Source

Usage

$
✓ Installed jotai v1.0.0

Getting Started

  1. Install the skill using the command above
  2. Open your AI coding agent (Claude Code, Codex, Gemini CLI, or Cursor)
  3. Reference the skill in your prompt
  4. The AI will use the skill's capabilities automatically

Example Prompts

  • "Review the open pull requests and summarize what needs attention"
  • "Generate a changelog from the last 20 commits on the main branch"

Documentation

Overview

Jotai is an atomic state management library for React. State is composed from independent atoms — each component subscribes only to the atoms it uses, getting automatic render optimization. Think of it as React.useState but shareable across components.

Instructions

Step 1: Primitive Atoms

typescript
// atoms/theme.ts — Basic atoms
import { atom, useAtom } from 'jotai'

export const themeAtom = atom<'light' | 'dark'>('light')
export const sidebarOpenAtom = atom(true)
export const countAtom = atom(0)

// Usage in any component
function ThemeToggle() {
  const [theme, setTheme] = useAtom(themeAtom)
  return (
    <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
      {theme === 'light' ? '🌙' : '☀️'}
    </button>
  )
}

Step 2: Derived Atoms

typescript
// atoms/cart.ts — Derived and async atoms
import { atom } from 'jotai'

interface CartItem { id: string; name: string; price: number; quantity: number }

export const cartItemsAtom = atom<CartItem[]>([])

// Read-only derived atom — recalculates when cartItemsAtom changes
export const cartTotalAtom = atom((get) => {
  const items = get(cartItemsAtom)
  return items.reduce((sum, item) => sum + item.price * item.quantity, 0)
})

export const cartCountAtom = atom((get) => {
  return get(cartItemsAtom).reduce((sum, item) => sum + item.quantity, 0)
})

// Write-only atom (action)
export const addToCartAtom = atom(null, (get, set, newItem: CartItem) => {
  const items = get(cartItemsAtom)
  const existing = items.find(i => i.id === newItem.id)
  if (existing) {
    set(cartItemsAtom, items.map(i =>
      i.id === newItem.id ? { ...i, quantity: i.quantity + 1 } : i
    ))
  } else {
    set(cartItemsAtom, [...items, { ...newItem, quantity: 1 }])
  }
})

Step 3: Async Atoms

typescript
// atoms/user.ts — Async data fetching atoms
import { atom } from 'jotai'

export const userIdAtom = atom<string | null>(null)

// Async derived atom — fetches when userIdAtom changes
export const userAtom = atom(async (get) => {
  const id = get(userIdAtom)
  if (!id) return null
  const res = await fetch(`/api/users/${id}`)
  return res.json()
})

Step 4: Persistence

typescript
import { atomWithStorage } from 'jotai/utils'

// Automatically syncs with localStorage
export const authTokenAtom = atomWithStorage<string | null>('auth-token', null)
export const preferencesAtom = atomWithStorage('preferences', {
  language: 'en',
  notifications: true,
})

Guidelines

  • Jotai atoms are bottom-up (compose small pieces); Zustand stores are top-down (one big object).
  • Use Jotai when state is granular and spread across many components.
  • Use Zustand when state is centralized (auth, app config, complex business logic).
  • atomWithStorage handles localStorage persistence with SSR support.
  • No Provider needed (uses default store), but Provider is available for testing/isolation.

Information

Version
1.0.0
Author
terminal-skills
Category
Development
License
Apache-2.0