Frontend & Accessibility

React Component Auditor

Check a component for the specific bugs React's model makes possible -- stale closures, missing dependency array entries, and unnecessary re-renders -- not general style.

When to use this

  • A new or changed React component uses hooks (useEffect, useMemo, useCallback) and needs a correctness check.
  • A component re-renders more than expected, or a `useEffect` behaves inconsistently.
  • Not for a general code-style review of the component -- use code-review for that; this is React-specific correctness.

The skill file

Copy this verbatim. It's written in the SKILL.md format (YAML frontmatter + markdown instructions) that Claude Code, and increasingly other agent tools, read directly.

SKILL.md
---
name: react-component-auditor
description: Review a React component for hook-specific correctness bugs -- missing or incorrect useEffect dependencies, stale closures, and unnecessary re-renders from unstable references -- rather than general style. Use for components with non-trivial hook usage.
---

# React Component Auditor

## useEffect dependency correctness

- Does the dependency array include every value from component scope
  that the effect actually reads? A missing dependency means the effect
  captures a stale value from an earlier render (a stale closure) instead
  of the current one.
- Conversely, is anything in the dependency array that shouldn't trigger
  a re-run (e.g. an object/function recreated every render, causing the
  effect to fire every render even though nothing meaningful changed)?
- Does an effect with a subscription/timer/listener clean up correctly in
  its return function, so it doesn't leak or double-fire across re-mounts
  (especially with React 18 Strict Mode's double-invoke in development)?

## Stale closures outside useEffect

- Does an event handler or callback capture a value from an earlier
  render via closure, when it should be reading current state (check
  whether it should use a ref, or the functional form of a state setter,
  instead)?

## Unnecessary re-renders

- Is a new object/array/function literal created inline in JSX props on
  every render, defeating a child component's `memo`/`useMemo`/
  `useCallback` optimization?
- Is `useMemo`/`useCallback` used where the computation/function is cheap
  enough that memoizing it costs more than it saves (the dependency-array
  comparison itself isn't free)?

## Key prop correctness

- In a list render, is `key` a stable, unique identifier for the item
  (not array index, unless the list is truly static and never reordered/
  filtered)?

## Output

Findings with the specific hook/line, what's wrong (stale closure /
missing cleanup / unstable reference), and the concrete fix.

Installing it elsewhere

The frontmatter/body split above is Claude Code's convention. Here's how to carry the same instructions into other tools:

Claude Code
.claude/skills/react-component-auditor/SKILL.md

Save the file below verbatim (frontmatter included) at that path, project-local or in ~/.claude/skills/ for a user-level skill. Claude Code loads the name/description pair to decide when to pull it in, or you invoke it directly as /react-component-auditor.

Cursor
.cursor/rules/react-component-auditor.mdc

Convert the YAML frontmatter to Cursor's rule format (description, globs, alwaysApply: false) and keep the markdown body as the rule content. Cursor surfaces it by description match, same idea as Claude Code's auto-load.

Codex CLI / Copilot
AGENTS.md

Codex CLI (and increasingly other agentic CLIs) read AGENTS.md at the repo root as always-on instructions. Paste the markdown body under a heading like ## {title}; for GitHub Copilot's coding agent, the equivalent file is .github/copilot-instructions.md.

Windsurf
.windsurfrules

Append the markdown body to .windsurfrules at the repo root. Windsurf treats the whole file as always-on context, so keep only the instructions you want applied on every request.

Where this goes wrong
  • Flagging every useEffect with a large dependency array as a problem without checking whether each dependency is actually needed.
  • Recommending useMemo/useCallback everywhere instead of only where the render cost or referential-stability need actually justifies it.
  • Missing that array-index keys break state on reorder/filter/insert, not just on obviously-dynamic lists.