From harness-claude
Builds bottom-up atomic state with Jotai for granular, composable React state management like form fields, toggles, filters, and auto-updating derived atoms.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Build bottom-up atomic state with Jotai for granular, composable React state management
Wires Jotai atoms as state backend for json-render via @json-render/jotai. Use when integrating Jotai state management with json-render React components.
Guides 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 patterns with Redux Toolkit, Zustand, Jotai, React Query for local, global, server state, and library selection.
Share bugs, ideas, or general feedback.
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