react-code-review について
Reactアプリの開発者向けに、コードを構造化してレビューするスキルです。マージ前の確認やリファクタリング後の評価に使え、重要度別の指摘、良い点、コード例付きの優先提案をまとめます。
主な機能
- 01Reactコンポーネントとフックの確認
- 02React 19パターンのレビュー
- 03アクセシビリティとTypeScriptの確認
- 04アーキテクチャと性能の分析
- 05重要度別の指摘と提案
活用シーン
- 01マージ前のReact変更のレビュー
- 02インタラクティブなコンポーネントのアクセシビリティ確認
- 03フックの依存関係やクリーンアップの問題発見
- 04状態管理と性能方針の評価
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ giuseppe-trisciuoglio/ developer-kit --skill react-code-reviewインストール後、Claude Code で/react-code-reviewを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/accessibility.mdcomponent-architecture.mdhooks-patterns.md詳細
React コードレビュー
概要
このスキルは、React アプリケーションの構造化された包括的なコードレビューを提供します。React 19 のベストプラクティス、コンポーネントアーキテクチャのパターン、フックの使用方法、アクセシビリティ基準、本番環境への対応状況に照らしてコードを評価します。レビューでは、重要度(重大、警告、提案)別に分類した、改善のための具体的なコード例を含む実行可能な指摘事項を提示します。
エージェントシステム経由で呼び出された場合、このスキルは詳細なアーキテクチャ分析を react-software-architect-review エージェントに委任します。
使用する場面
- マージ前に React コンポーネント、フック、ページをレビューする
- コンポーネントの構成と再利用性のパターンを検証する
- フックが適切に使用されているか確認する(useState、useEffect、useMemo、useCallback)
- React 19 のパターンをレビューする(use、useOptimistic、useFormStatus、Actions)
- 状態管理のアプローチを評価する(ローカル、コンテキスト、外部ストア)
- パフォーマンス最適化を評価する(メモ化、コード分割、遅延読み込み)
- アクセシビリティへの準拠状況をレビューする(WCAG、セマンティック HTML、ARIA)
- props、state、イベントの TypeScript 型付けを検証する
- Tailwind CSS とスタイリングのパターンを確認する
- 新しい React 機能を実装した後や、コンポーネントアーキテクチャをリファクタリングした後
手順
-
対象範囲を特定する:レビュー対象の React コンポーネントとフックを特定します。
globを使用して.tsx/.jsxファイルを検出し、grepを使用してコンポーネント定義、フックの使用箇所、コンテキストプロバイダーを特定します。 -
コンポーネントアーキテクチャを分析する:コンポーネントが適切に構成されていることを確認します。単一責任、適切なサイズ、再利用性をチェックします。大きすぎるコンポーネント(200 行超)、props が多すぎるコンポーネント(7 個超)、または関心事が混在しているコンポーネントを探します。
-
フックの使用状況をレビューする:フックが適切に使用されていることを検証します。
useEffect/useMemo/useCallbackの依存配列をチェックし、useEffectのクリーンアップ関数を確認して、メモ化の不足や誤りによる不要な再レンダリングを特定します。 -
状態管理を評価する:状態の配置を評価します。適切なコロケーション、不必要な状態のリフトアップ、Context と外部ストアの適切な使い分けを確認します。サーバー状態には、手動の
useEffect+useStateパターンではなく、TanStack Query、SWR、または同様のライブラリが使用されていることを確認します。 -
アクセシビリティを確認する:セマンティック HTML の使用、ARIA 属性、キーボード操作、フォーカス管理、スクリーンリーダーとの互換性をレビューします。操作可能な要素がアクセシブルであり、フォーム入力に適切なラベルが付いていることを確認します。
-
パフォーマンスを評価する:不要な再レンダリング、高負荷のコンポーネントに対する
React.memoの不足、useCallback/useMemoの不適切な使用、コード分割の不足、大きなバンドルを招くインポートを探します。 -
TypeScript との統合をレビューする:props の型定義、イベントハンドラーの型付け、ジェネリックコンポーネントのパターン、ユーティリティ型の適切な使用を確認します。具体的な型を使用できる箇所で
anyが使われていないことを確認します。 -
レビューレポートを作成する:重要度別の指摘事項(重大、警告、提案)、肯定的な所見、優先順位を付けた推奨事項をコード例とともに含む、構造化されたレポートを作成します。
例
例 1:フックの依存関係の問題
// ❌ Bad: Missing dependency causes stale closure
function UserProfile({ userId }: { userId: string }) {
const [user, setUser] = useState<User | null>(null);
useEffect(() => {
fetchUser(userId).then(setUser);
}, []); // Missing userId in dependency array
return <div>{user?.name}</div>;
}
// ✅ Good: Proper dependencies with cleanup
function UserProfile({ userId }: { userId: string }) {
const [user, setUser] = useState<User | null>(null);
useEffect(() => {
let cancelled = false;
fetchUser(userId).then((data) => {
if (!cancelled) setUser(data);
});
return () => { cancelled = true; };
}, [userId]);
return <div>{user?.name}</div>;
}
// ✅ Better: Use TanStack Query for server state
function UserProfile({ userId }: { userId: string }) {
const { data: user, isLoading } = useQuery({
queryKey: ['user', userId],
queryFn: () => fetchUser(userId),
});
if (isLoading) return <Skeleton />;
return <div>{user?.name}</div>;
}
例 2:コンポーネントの構成
// ❌ Bad: Monolithic component mixing data fetching, filtering, and rendering
function Dashboard() {
const [users, setUsers] = useState([]);
const [filter, setFilter] = useState('');
useEffect(() => { /* fetch + filter + sort all in one */ }, [filter]);
return <div>{/* 200+ lines of mixed concerns */}</div>;
}
// ✅ Good: Composed from focused components with custom hooks
function Dashboard() {
return (
<div>
<UserFilters />
<Suspense fallback={<TableSkeleton />}>
<UserTable />
</Suspense>
<UserPagination />
</div>
);
}
例 3:アクセシビリティレビュー
// ❌ Bad: Inaccessible interactive elements
function Menu({ items }: { items: MenuItem[] }) {
const [open, setOpen] = useState(false);
return (
<div>
<div onClick={() => setOpen(!open)}>Menu</div>
{open && (
<div>
{items.map(item => (
<div key={item.id} onClick={() => navigate(item.path)}>
{item.label}
</div>
))}
</div>
)}
</div>
);
}
// ✅ Good: Accessible with proper semantics and keyboard support
function Menu({ items }: { items: MenuItem[] }) {
const [open, setOpen] = useState(false);
return (
<nav aria-label="Main navigation">
<button
onClick={() => setOpen(!open)}
aria-expanded={open}
aria-controls="menu-list"
>
Menu
</button>
{open && (
<ul id="menu-list" role="menu">
{items.map(item => (
<li key={item.id} role="menuitem">
<a href={item.path}>{item.label}</a>
</li>
))}
</ul>
)}
</nav>
);
}
例 4:パフォーマンス最適化
// ❌ Bad: Unstable callback recreated every render causes child re-renders
{filtered.map(product => (
<ProductCard
key={product.id}
product={product}
onSelect={() => console.log(product.id)} // New function each render
/>
))}
// ✅ Good: Stable callback + memoized child
const handleSelect = useCallback((id: string) => {
console.log(id);
}, []);
const filtered = useMemo(
() => products.filter(p => p.name.toLowerCase().includes(search.toLowerCase())),
[products, search]
);
{filtered.map(product => (
<ProductCard key={product.id} product={product} onSelect={handleSelect} />
))}
const ProductCard = memo(function ProductCard({ product, onSelect }: Props) {
return <div onClick={() => onSelect(product.id)}>{product.name}</div>;
});
例 5:TypeScript の props レビュー
// ❌ Bad: Loose typing and missing prop definitions
function Card({ data, onClick, children, ...rest }: any) {
return (
<div onClick={onClick} {...rest}>
<h2>{data.title}</h2>
{children}
</div>
);
}
// ✅ Good: Strict typing with proper interfaces
interface CardProps extends React.ComponentPropsWithoutRef<'article'> {
title: string;
description?: string;
variant?: 'default' | 'outlined' | 'elevated';
onAction?: (event: React.MouseEvent<HTMLButtonElement>) => void;
children: React.ReactNode;
}
function Card({
title,
description,
variant = 'default',
onAction,
children,
className,
...rest
}: CardProps) {
return (
<article className={cn('card', `card--${variant}`, className)} {...rest}>
<h2>{title}</h2>
{description && <p>{description}</p>}
{children}
{onAction && <button onClick={onAction}>Action</button>}
</article>
);
}
レビュー出力形式
すべてのコードレビューの指摘事項を、次の形式で構成してください。
1. 概要
全体的な品質スコア(1~10)と主な所見を含む簡潔な概要。
2. 重大な問題(修正必須)
バグ、セキュリティ上の脆弱性、または機能の破損を引き起こす問題。
3. 警告(修正を推奨)
ベストプラクティスに反する問題、パフォーマンスの問題を引き起こす問題、または保守性を低下させる問題。
4. 提案(改善を検討)
コード構成、アクセシビリティ、または開発者エクスペリエンスの改善。
5. 肯定的な所見
評価すべき、適切に実装されたパターンや優れたプラクティス。
6. 推奨事項
特に効果の大きい改善に向けて、優先順位を付けた次のステップとコード例を示します。
ベストプラクティス
- コンポーネントの役割を絞り、単一責任にして、200行未満にします
- 状態は、それを使用するコンポーネントの近くに配置します
- カスタムフックを使って、再利用可能なロジックをコンポーネントから切り出します
React.memoは、再レンダリングのコストを測定したうえで、その適用に見合う場合にのみ使用します- サーバーの状態には、
useEffectとuseStateの組み合わせではなく、TanStack Query または SWR を使用します - 外部リソースを購読する場合は、
useEffectに必ずクリーンアップ関数を含めます - まずセマンティック HTML を使用し、ネイティブのセマンティクスでは不十分な場合にのみ ARIA を追加します
- TypeScript の strict モードを使用し、コンポーネントの props で
anyを避けます - エラー境界を実装して、障害を適切に処理します
- 条件付きレンダリングが複雑になる場合は、条件分岐よりコンポジションを優先します
制約と警告
- プロジェクトの React バージョンに従い、古いバージョンでは React 19 の機能を提案しないでください
- プロジェクトで特定の状態管理ライブラリを標準化していない限り、そのライブラリを強制しないでください
- メモ化が常に効果的とは限りません。再レンダリングへの影響を測定できる場合にのみ提案してください
- アクセシビリティの推奨事項は、ベースラインとして WCAG 2.1 AA に従ってください
- 信頼性の高い問題に焦点を当て、主観的なスタイルの選択に対する誤検出を避けてください
- 明確で測定可能なメリットがない限り、正常に動作しているコンポーネントの書き換えを提案しないでください
参考資料
詳細なレビュー用チェックリストとパターンのドキュメントについては、references/ ディレクトリを参照してください。
references/hooks-patterns.md— React フックのベストプラクティスとよくある間違いreferences/component-architecture.md— コンポーネントのコンポジションと設計パターンreferences/accessibility.md— React のアクセシビリティチェックリストと ARIA パターン