From harness-claude
Selects and derives state efficiently to minimize component re-renders across Zustand, Redux, Jotai, or React Context.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:state-selection-patternsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Select and derive state efficiently to minimize component re-renders across any state management library
Select and derive state efficiently to minimize component re-renders across any state management library
// Pattern 1: Zustand — inline selector
const userName = useStore((s) => s.user.name);
// Only re-renders when user.name changes (reference equality)
// Pattern 2: Zustand — multiple fields with useShallow
import { useShallow } from 'zustand/react/shallow';
const { name, email } = useStore(useShallow((s) => ({ name: s.user.name, email: s.user.email })));
// Pattern 3: Redux — createSelector for derived data
import { createSelector } from '@reduxjs/toolkit';
const selectTodos = (state: RootState) => state.todos.items;
const selectFilter = (state: RootState) => state.todos.filter;
const selectVisibleTodos = createSelector(
[selectTodos, selectFilter],
(todos, filter) => {
if (filter === 'all') return todos;
return todos.filter((t) => (filter === 'completed' ? t.completed : !t.completed));
}
);
// Pattern 4: Jotai — derived atoms
const visibleTodosAtom = atom((get) => {
const todos = get(todosAtom);
const filter = get(filterAtom);
return filter === 'all' ? todos : todos.filter((t) => t.completed === (filter === 'completed'));
});
// Pattern 5: useMemo for component-level derivations
function FilteredList({ filter }: { filter: string }) {
const items = useStore((s) => s.items);
const filtered = useMemo(
() => items.filter((i) => i.category === filter),
[items, filter]
);
return <List items={filtered} />;
}
Why reference equality matters: React and state libraries use Object.is (reference equality) to decide if a component should re-render. If your selector returns todos.filter(...), it creates a new array on every call, even if the contents are identical. The component re-renders every time.
Memoization strategies by library:
| Library | Strategy | Tool |
|---|---|---|
| Redux | Input memoization | createSelector (Reselect) |
| Zustand | Shallow equality | useShallow |
| Jotai | Atom dependency graph | Derived atoms |
| React | Component-level memo | useMemo |
Selector composition pattern:
// Base selectors (simple accessors)
const selectUsers = (state: RootState) => state.users.items;
const selectCurrentUserId = (state: RootState) => state.auth.userId;
// Composed selector (derived from base selectors)
const selectCurrentUser = createSelector([selectUsers, selectCurrentUserId], (users, userId) =>
users.find((u) => u.id === userId)
);
// Further composition
const selectCurrentUserPosts = createSelector([selectCurrentUser, selectPosts], (user, posts) =>
user ? posts.filter((p) => p.authorId === user.id) : []
);
When NOT to memoize: Primitive values (numbers, strings, booleans) are compared by value. useStore((s) => s.count) never creates a new reference — no memoization needed. Only memoize when the selector returns objects, arrays, or computes derived data.
Performance debugging: Use React DevTools Profiler to identify components that re-render unnecessarily. Check what selector results change between renders. Use why-did-you-render for automated detection.
https://react.dev/reference/react/useMemo
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeOptimizes Zustand re-renders by guiding use of selectors, shallow comparison, useShallow, and transient subscriptions for performance-sensitive UIs.
Guides state management decisions (local vs global), store structure, selectors, and re-render performance. Useful when creating stores or managing client-side state. Examples use Zustand.
Provides Zustand 5.x patterns for React state management: slices, middleware, Immer, useShallow, persistence, selectors, devtools, async actions, and anti-patterns with TanStack Query integration. Use for global client state without boilerplate.