You are a senior React engineer. Review all React/TSX files changed in the current branch. For each finding, report:
- Severity: High / Medium / Low
- Location: file:line
- Issue: concise description of the problem
- Recommendation: concrete, actionable fix
If a category is clean, say so briefly. Do not skip categories.
How to gather the diff
Run:
git diff main...HEAD
Focus on .tsx, .ts, .jsx, .js files. Read additional context from related files as needed.
Review Checklist
1. Component Design & Hooks
Component responsibilities
- Components doing too much — rendering, data fetching, business logic, and formatting all in one
- Recommendation: split into a container (data/logic) and a presentational (render-only) component
Prop drilling
- Props passed through 3+ levels of components that don't use them
- Recommendation: lift to context, a store, or colocate the consuming component closer to the data
Component size
- Components exceeding ~150 lines or containing more than one distinct visual section
- Recommendation: extract sub-components with descriptive names
useEffect misuse
- Effects used to sync derived state that could be computed inline or with
useMemo
- Effects that run on every render due to missing or incorrectly specified dependency arrays
- Multiple unrelated concerns in a single
useEffect
- Missing cleanup for subscriptions, timers, or event listeners
- Recommendation: compute derived values inline; split effects by concern; always return cleanup functions
Stale closures
- Variables captured in callbacks or effects that don't reflect the latest state/props
- Common in
setInterval, event listeners, or async callbacks not listed in deps
- Recommendation: add to dependency array; use
useRef for values that should not re-trigger effects
Hook ordering violations
- Hooks called conditionally or inside loops
- Recommendation: move hooks to top level; use conditional logic inside the hook body
Custom hook opportunities
- Repeated stateful logic across multiple components that could be extracted
- Recommendation: extract to a
use* custom hook in a shared location
2. Performance
Unnecessary re-renders
- Components re-rendering because a parent passes a new object/array literal or inline function on every render
- Recommendation: memoize with
useMemo / useCallback; stabilize references
Missing React.memo
- Pure presentational components that receive stable props but aren't memoized
- Recommendation: wrap with
React.memo where the component is expensive to render
Expensive computations in render
- Heavy calculations or data transformations done inline during render without
useMemo
- Recommendation: memoize with
useMemo; move to a selector or derived query
Large component trees without lazy loading
- Heavy components or routes not using
React.lazy / Suspense
- Recommendation: code-split at route or modal boundaries
Key prop issues
- Missing
key props in lists; using array index as key for reorderable lists
- Recommendation: use stable, unique IDs as keys
3. Accessibility (a11y)
Missing or incorrect ARIA
- Interactive elements lacking
aria-label / aria-labelledby when no visible text is present
role attributes used incorrectly or unnecessarily (avoid overriding native semantics)
- Dynamic content changes not announced via
aria-live
Keyboard navigation
- Click handlers on non-interactive elements (
div, span) without a corresponding onKeyDown/onKeyPress and tabIndex
- Focus not managed after modal open/close or route transitions
- Custom dropdowns, dialogs, or menus that don't implement expected keyboard patterns (Escape to close, arrow key navigation)
Focus management
- Modals that don't trap focus or don't return focus to the trigger on close
- Skip-to-content links missing on new pages
Semantic HTML
- Using
<div> or <span> where a semantic element (<button>, <nav>, <main>, <section>) is appropriate
- Form inputs missing associated
<label> elements
Color & contrast
- Inline styles or new CSS that introduce text/background color combinations — flag for manual contrast check (tool cannot verify ratios, but can identify new color declarations to review)
4. State Management
Unnecessary state
- State that is fully derivable from other state or props and doesn't need to be stored
- Recommendation: compute inline or with
useMemo; remove the useState
Local vs global state
- UI-only state (open/closed, hover, form input) stored in global state/context unnecessarily
- Shared cross-component state managed locally, causing sync bugs
- Recommendation: keep UI state local; lift or globalize only when multiple disconnected components need it
Apollo / GraphQL cache
- Queries that bypass the cache with
fetchPolicy: 'network-only' without clear justification
- Manual cache writes (
writeQuery, writeFragment) that could cause stale data
- Missing
optimisticResponse on mutations where latency would hurt UX
- Over-fetching: queries selecting more fields than the component uses
Stale or redundant state after data fetches
- Local state that mirrors remote data and can get out of sync
- Recommendation: derive from the query result directly; avoid duplicating server state locally
5. Testing Patterns (React/TSX)
When reviewing *.test.tsx changes, apply the React testing rules in .claude/rules/testing/react.md in addition to the general FXA rules in .claude/rules/testing/base.md. Both rules auto-load when Claude reads a matching test file; this skill's pre-flight should explicitly Read them too so reviews cover test changes consistently. Headline triggers to flag: implementation-detail queries (className/CSS/data-testid where semantic queries fit), fireEvent where userEvent belongs, asserting on instances/refs/private state, missing or misused act(), whole-tree snapshots for non-trivial components, and duplicated provider boilerplate.
Output Format
Lead with a summary table of all findings (severity, category, file:line, one-line description). Follow with detailed write-ups for High severity items. End with a "Clean categories" list for anything with no issues found.
1---2name: fxa-check-react3description: Reviews changed React/TSX code for component design, hooks misuse, performance, accessibility, and state management issues. Reports findings with severity and concrete fix recommendations. Operates on files changed vs main.4---56You are a senior React engineer. Review all React/TSX files changed in the current branch. For each finding, report:7- **Severity**: High / Medium / Low8- **Location**: file:line9- **Issue**: concise description of the problem10- **Recommendation**: concrete, actionable fix1112If a category is clean, say so briefly. Do not skip categories.1314## How to gather the diff1516Run:17```18git diff main...HEAD19```2021Focus on `.tsx`, `.ts`, `.jsx`, `.js` files. Read additional context from related files as needed.2223---2425## Review Checklist2627### 1. Component Design & Hooks2829**Component responsibilities**30- Components doing too much — rendering, data fetching, business logic, and formatting all in one31- Recommendation: split into a container (data/logic) and a presentational (render-only) component3233**Prop drilling**34- Props passed through 3+ levels of components that don't use them35- Recommendation: lift to context, a store, or colocate the consuming component closer to the data3637**Component size**38- Components exceeding ~150 lines or containing more than one distinct visual section39- Recommendation: extract sub-components with descriptive names4041**`useEffect` misuse**42- Effects used to sync derived state that could be computed inline or with `useMemo`43- Effects that run on every render due to missing or incorrectly specified dependency arrays44- Multiple unrelated concerns in a single `useEffect`45- Missing cleanup for subscriptions, timers, or event listeners46- Recommendation: compute derived values inline; split effects by concern; always return cleanup functions4748**Stale closures**49- Variables captured in callbacks or effects that don't reflect the latest state/props50- Common in `setInterval`, event listeners, or async callbacks not listed in deps51- Recommendation: add to dependency array; use `useRef` for values that should not re-trigger effects5253**Hook ordering violations**54- Hooks called conditionally or inside loops55- Recommendation: move hooks to top level; use conditional logic inside the hook body5657**Custom hook opportunities**58- Repeated stateful logic across multiple components that could be extracted59- Recommendation: extract to a `use*` custom hook in a shared location6061---6263### 2. Performance6465**Unnecessary re-renders**66- Components re-rendering because a parent passes a new object/array literal or inline function on every render67- Recommendation: memoize with `useMemo` / `useCallback`; stabilize references6869**Missing `React.memo`**70- Pure presentational components that receive stable props but aren't memoized71- Recommendation: wrap with `React.memo` where the component is expensive to render7273**Expensive computations in render**74- Heavy calculations or data transformations done inline during render without `useMemo`75- Recommendation: memoize with `useMemo`; move to a selector or derived query7677**Large component trees without lazy loading**78- Heavy components or routes not using `React.lazy` / `Suspense`79- Recommendation: code-split at route or modal boundaries8081**Key prop issues**82- Missing `key` props in lists; using array index as `key` for reorderable lists83- Recommendation: use stable, unique IDs as keys8485---8687### 3. Accessibility (a11y)8889**Missing or incorrect ARIA**90- Interactive elements lacking `aria-label` / `aria-labelledby` when no visible text is present91- `role` attributes used incorrectly or unnecessarily (avoid overriding native semantics)92- Dynamic content changes not announced via `aria-live`9394**Keyboard navigation**95- Click handlers on non-interactive elements (`div`, `span`) without a corresponding `onKeyDown`/`onKeyPress` and `tabIndex`96- Focus not managed after modal open/close or route transitions97- Custom dropdowns, dialogs, or menus that don't implement expected keyboard patterns (Escape to close, arrow key navigation)9899**Focus management**100- Modals that don't trap focus or don't return focus to the trigger on close101- Skip-to-content links missing on new pages102103**Semantic HTML**104- Using `<div>` or `<span>` where a semantic element (`<button>`, `<nav>`, `<main>`, `<section>`) is appropriate105- Form inputs missing associated `<label>` elements106107**Color & contrast**108- Inline styles or new CSS that introduce text/background color combinations — flag for manual contrast check (tool cannot verify ratios, but can identify new color declarations to review)109110---111112### 4. State Management113114**Unnecessary state**115- State that is fully derivable from other state or props and doesn't need to be stored116- Recommendation: compute inline or with `useMemo`; remove the `useState`117118**Local vs global state**119- UI-only state (open/closed, hover, form input) stored in global state/context unnecessarily120- Shared cross-component state managed locally, causing sync bugs121- Recommendation: keep UI state local; lift or globalize only when multiple disconnected components need it122123**Apollo / GraphQL cache**124- Queries that bypass the cache with `fetchPolicy: 'network-only'` without clear justification125- Manual cache writes (`writeQuery`, `writeFragment`) that could cause stale data126- Missing `optimisticResponse` on mutations where latency would hurt UX127- Over-fetching: queries selecting more fields than the component uses128129**Stale or redundant state after data fetches**130- Local state that mirrors remote data and can get out of sync131- Recommendation: derive from the query result directly; avoid duplicating server state locally132133---134135### 5. Testing Patterns (React/TSX)136137When reviewing `*.test.tsx` changes, apply the React testing rules in `.claude/rules/testing/react.md` in addition to the general FXA rules in `.claude/rules/testing/base.md`. Both rules auto-load when Claude reads a matching test file; this skill's pre-flight should explicitly `Read` them too so reviews cover test changes consistently. Headline triggers to flag: implementation-detail queries (className/CSS/data-testid where semantic queries fit), `fireEvent` where `userEvent` belongs, asserting on instances/refs/private state, missing or misused `act()`, whole-tree snapshots for non-trivial components, and duplicated provider boilerplate.138139---140141## Output Format142143Lead with a **summary table** of all findings (severity, category, file:line, one-line description). Follow with detailed write-ups for High severity items. End with a **"Clean categories"** list for anything with no issues found.