From harness-claude
Manages atomic state with Jotai for granular, composable React state management. Covers primitive atoms, derived atoms, and writable derived atoms with useAtom, useAtomValue, and useSetAtom.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:state-jotai-atomsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Build bottom-up atomic state with Jotai for granular, composable React state management
Build bottom-up atomic state with Jotai for granular, composable React state management
atom(initialValue). These are the smallest units of state.atom((get) => computation). They auto-update when dependencies change.atom(readFn, writeFn) for computed state with custom setters.useAtom in components — it returns [value, setValue] like useState.useAtomValue for read-only access and useSetAtom for write-only access to minimize subscriptions.atoms/auth.ts, atoms/cart.ts).<Provider> only for scoped state or testing.// atoms/cart.ts
import { atom } from 'jotai';
interface CartItem {
id: string;
name: string;
price: number;
qty: number;
}
// Primitive atoms
export const cartItemsAtom = atom<CartItem[]>([]);
export const couponCodeAtom = atom<string | null>(null);
// Derived atom (read-only) — auto-updates when cartItemsAtom changes
export const cartTotalAtom = atom((get) => {
const items = get(cartItemsAtom);
return items.reduce((sum, item) => sum + item.price * item.qty, 0);
});
export const cartCountAtom = atom((get) => {
return get(cartItemsAtom).reduce((sum, item) => sum + item.qty, 0);
});
// Derived atom with discount applied
export const discountedTotalAtom = atom((get) => {
const total = get(cartTotalAtom);
const coupon = get(couponCodeAtom);
return coupon ? total * 0.9 : total;
});
// Writable derived atom — custom setter
export const addToCartAtom = atom(
null, // read value (null = write-only)
(get, set, newItem: Omit<CartItem, 'qty'>) => {
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, qty: i.qty + 1 } : i))
);
} else {
set(cartItemsAtom, [...items, { ...newItem, qty: 1 }]);
}
}
);
// Component usage
import { useAtomValue, useSetAtom } from 'jotai';
function CartSummary() {
const total = useAtomValue(discountedTotalAtom); // Read-only, re-renders only when total changes
const count = useAtomValue(cartCountAtom);
return <div>{count} items - ${total.toFixed(2)}</div>;
}
function AddButton({ product }: { product: { id: string; name: string; price: number } }) {
const addToCart = useSetAtom(addToCartAtom); // Write-only, never re-renders from this atom
return <button onClick={() => addToCart(product)}>Add to Cart</button>;
}
Atom dependency graph: Derived atoms automatically track which atoms they read via get(). When any dependency changes, the derived atom recomputes. This is reactive — no manual subscription management.
Async atoms: Atoms can return promises. Jotai integrates with React Suspense:
const userAtom = atom(async () => {
const res = await fetch('/api/user');
return res.json();
});
// Component suspends until data loads
function User() {
const user = useAtomValue(userAtom); // Suspends, then returns data
return <div>{user.name}</div>;
}
atomWithStorage: Persist atoms to localStorage:
import { atomWithStorage } from 'jotai/utils';
const themeAtom = atomWithStorage('theme', 'light');
// Automatically reads from and writes to localStorage
Jotai vs Zustand: Jotai is bottom-up (compose small atoms into larger state). Zustand is top-down (define a store, select slices). Choose Jotai when state is naturally fragmented across many components. Choose Zustand when state is a cohesive domain object.
Jotai vs React Context: Both are Provider-based. But Context re-renders all consumers when any value changes. Jotai only re-renders consumers of the specific atom that changed.
Testing: Use <Provider> in tests to create isolated atom scopes:
import { Provider, createStore } from 'jotai';
const store = createStore();
store.set(cartItemsAtom, mockItems);
render(
<Provider store={store}>
<CartSummary />
</Provider>
);
https://jotai.org/docs/introduction
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeGuides React state management with useState, useReducer, Context, Zustand, Jotai, TanStack Query, SWR. Covers store setup, optimization, server caching, optimistic updates, normalization.
Guides React state management with Redux Toolkit, Zustand, Jotai, and React Query. Use when setting up global state, managing server state, or choosing between solutions.
Guides React state management patterns with Redux Toolkit, Zustand, Jotai, React Query for local, global, server state, and library selection.