install
source · Clone the upstream repo
git clone https://github.com/Intense-Visions/harness-engineering
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/skills/claude-code/redux-selectors-pattern" ~/.claude/skills/intense-visions-harness-engineering-redux-selectors-pattern && rm -rf "$T"
manifest:
agents/skills/claude-code/redux-selectors-pattern/SKILL.mdsource content
Redux Selectors Pattern
Derive and memoize computed state with createSelector to avoid redundant calculations and unnecessary re-renders
When to Use
- Computing derived data from Redux state (filtered lists, totals, lookups)
- Preventing re-renders caused by creating new array/object references on every selector call
- Composing complex selectors from simpler building blocks
- Parameterizing selectors (e.g., select items by category)
Instructions
- Co-locate simple selectors with the slice that owns the state. Export them from the slice file.
- Use
fromcreateSelector
(re-exported from Reselect) for any computation that produces derived data.@reduxjs/toolkit - Input selectors should be simple property accessors — no computation. Only the result function should do work.
- Compose selectors by passing other selectors as inputs. Never reach into
from outside the slice boundary.state.someSlice.nested.field - For parameterized selectors, create a factory function that returns a new selector per parameter value.
- Keep the selector return type stable — returning a new array/object reference defeats memoization.
// features/todos/todos.selectors.ts import { createSelector } from '@reduxjs/toolkit'; import { RootState } from '../../store'; // Simple selectors (no memoization needed) const selectTodosState = (state: RootState) => state.todos; export const selectAllTodos = (state: RootState) => state.todos.items; export const selectFilter = (state: RootState) => state.todos.filter; // Memoized derived selector export const selectFilteredTodos = createSelector( [selectAllTodos, selectFilter], (todos, filter) => { switch (filter) { case 'active': return todos.filter((t) => !t.completed); case 'completed': return todos.filter((t) => t.completed); default: return todos; } } ); // Composed selector export const selectTodoStats = createSelector([selectAllTodos], (todos) => ({ total: todos.length, completed: todos.filter((t) => t.completed).length, active: todos.filter((t) => !t.completed).length, })); // Parameterized selector factory export const makeSelectTodoById = (id: string) => createSelector([selectAllTodos], (todos) => todos.find((t) => t.id === id));
Details
How memoization works:
createSelector caches the last result. If all input selectors return the same references as last time, the result function is skipped and the cached result is returned. This is reference equality, not deep equality.
Common memoization mistakes:
- Inline
inside a component — creates a new selector instance on every render, defeating memoization. Move selectors outside components or usecreateSelector
.useMemo - Input selectors that do computation — the result function is skipped only when inputs are referentially equal. If an input selector creates a new object, memoization never works.
- Returning
from a simple selector (notitems.filter(...)
) — creates a new array every time, causing re-renders.createSelector
Per-component memoization: When multiple component instances need the same parameterized selector with different args, use a factory with
useMemo:
function TodoItem({ id }: { id: string }) { const selectTodo = useMemo(() => makeSelectTodoById(id), [id]); const todo = useAppSelector(selectTodo); // Each TodoItem has its own memoized selector }
Reselect 5.0+ (RTK 2.0+): Supports
createSelector with custom equality checks and weakMapMemoize for multi-argument caching without factories.
Testing selectors: Test them as pure functions — pass in a mock
RootState and assert the output. They are the easiest Redux code to test.
Source
https://redux-toolkit.js.org/api/createSelector
Process
- Read the instructions and examples in this document.
- Apply the patterns to your implementation, adapting to your specific context.
- Verify your implementation against the details and edge cases listed above.
Harness Integration
- Type: knowledge — this skill is a reference document, not a procedural workflow.
- No tools or state — consumed as context by other skills and agents.
Success Criteria
- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.