Reactのレビュー基準を公式ドキュメントに揃えたいので、Claude Codeで50項目のチェックリストを作ってみた話

Reactのレビュー基準を公式ドキュメントに揃えたいので、Claude Codeで50項目のチェックリストを作ってみた話

React公式ドキュメントを基にした、50項目のコードレビューチェックリストを作成しました。感覚的なコメントから脱却し、公式の推奨事項を根拠にしたレビューを実現する方法と、実際の適用結果を共有します。
2026.10.22

こんにちは。リテールアプリ共創部の中村です。

みなさん、普段のPR前コードレビューはどのように運用していますか?

私は、独自の判断基準を持たせたサブエージェントにレビューをさせる運用にしていましたが、本当にこれで正しい実装になっているのか?と不安に思うことが多くありました。Reactに関しては経験が浅いということもあり、特に実装やレビューに自信を持てていませんでした。

そこで今回、公式ドキュメント(react.dev)を Claude Code に読み込ませて、公式の推奨事項に基づいた50項目のコードレビュー用チェックリストを作成してみました。本記事では、その作成アプローチや実際のチェックリスト、使ってみて腑に落ちたポイントを共有します。

1. Claude Code にどう読ませたか

公式ドキュメントのHTMLページをそのままクローリングすると余計な情報が混ざりやすいため、以下のようなステップで効率的に読み込ませました。

  1. 目次の取得: https://react.dev/llms.txt(AI向けに各ドキュメントのMarkdownリンクをまとめたファイル)を活用
  2. Markdown原文の取得: HTMLではなく、装飾やノイズのない純粋なMarkdownを取得
  3. エージェントによる分担読み込み: Learn(入門・解説)の全51ページをサブエージェント3体で分担し、Rules of ReactやLint規則、React 19関連の差分はメイン側で精読
  4. チェックリストの生成: 根拠となる公式の節名を添えて全50項目に整理
  5. 差分レビューへの適用: 変更した行に対してリストの観点を当てはめる

HTML要約を挟まず、ドキュメントの原文や「Pitfall(落とし穴)」セクションを直接読ませることで、公式の意図を読み取りやすかったと感じています。

2. チェックリストの設計と全体像

できあがったチェックリストは、全50項目です。

カテゴリ 明確な違反 推奨事項 合計
描画の純粋性(P) 5 0 5
フックの規則(H) 3 0 3
Refの扱い(R) 1 2 3
副作用・Effect(E) 2 11 13
状態とイベント(S) 4 9 13
カスタムフック(C) 0 3 3
Propsとコンポーネント合成(K) 0 6 6
テスト(T) 1 3 4

Effect と State(状態管理)だけで全体の約半分を占めており、やはり現場で悩みやすいポイントがそのまま反映された印象です。

「明確な違反」と「推奨」の切り分け

レビューが形骸化したり不毛な議論になったりするのを防ぐため、重要度を2つに分類しました。

  • ● 明確な違反(16項目): 公式ルール違反、または確実にバグになるもの(S-1〜S-4・T-1など)(理由があっても原則修正を依頼)
  • ○ 推奨(34項目): 公式が推奨する標準的な設計パターン(設計意図や明確な理由があるなら許容)

1項目のフォーマット

各項目には「問い・違反例・改善案・根拠(節名)」を明記しています。

R-1 描画中に ref.current を読み書きしていないか 【lint対象】

  • 違反例: latestFnRef.current = fn;(描画中に直接代入)
  • 改善案: 代入を useEffect の中に移す。Effect内からのみ呼ぶ関数なら useEffectEvent を検討する
  • 根拠: reference/react/useRef.md の Pitfall("Do not write or read ref.current during rendering")

※ なお、Biome などのリンターで拾える静的検証(フックの呼び出し位置や依存配列など)もありますが、静的解析だけでは検知しきれない設計意図の部分を目視レビューで補う方針をとっています。

3. チェックリスト全項目とポイント

各カテゴリで特に重要だと感じたポイントとともに、リストを紹介します。

  • 表の見方:●=明確な違反 / ○=推奨 / lint=eslint-plugin-react-hooks等で検知可能な項目(「一部」は検知できない形がある項目)

3-1. 描画の純粋性(P)

Reactの更新は 「トリガー(きっかけ)→ レンダリング(描画計算)→ コミット(DOM反映)」 という流れを辿ります。レンダリング処理は何回実行されても安全なように、純粋な計算だけに留めるのが基本とされています。

Reactを給仕に見立てた3コマ。注文を厨房に届ける、厨房でCardを作る、テーブルに届ける
出典:Render and Commit|React(3枚の挿絵を横に並べて掲載)

ID 観点 改善案の目安
P-1 ● lint 描画中に副作用(外部変数の変更、DOM操作、通信等)を起こしていないか 操作由来ならイベントハンドラへ、表示との同期ならEffectへ移す
P-2 ● lint 描画中に Date.now() や Math.random() など毎回変わる値を使っていないか useState(() => ...) の初期化関数、またはハンドラ内で生成する
P-3 ● lint Props・State・フックの戻り値などを直接書き換えて(ミューテーションして)いないか スプレッド構文や toSorted() などで浅いコピーを作成して扱う
P-4 ● lint 描画中の setState を無条件に行うなど、レンダリングループを起こしていないか 単純な計算値で済まないか、key の変更で初期化できないか見直す
P-5 ● lint コンポーネントを関数として直接呼び出したり、内部で別のコンポーネントを定義したりしていないか JSXタグとして呼び出し、コンポーネント定義はモジュールのトップレベルで行う

3-2. フックの規則(H)

Reactはフックが呼ばれる「順番」を頼りに状態を内部管理しています。条件分岐の中でフックを呼ぶと、React内部の参照がずれて予期せぬ動作を招く恐れがあります。

Reactの周りの棚にstateが置かれ、クリックでsetIsSent(true)が届く挿絵
出典:State as a Snapshot|React

フックの呼び出し順と棚の対応(イメージ図)。実際には、呼ぶフックの数が変わるとReactはエラーで止まる

ID 観点 改善案の目安
H-1 ● lint 条件分岐・ループ・早期returnの後・ハンドラ内でフックを呼んでいないか 早期returnより前に記述する。条件付きにしたい場合はコンポーネント自体を分離する
H-2 ● lint 通常の関数からフックを呼んだり、フックを値として渡したりしていないか コンポーネントまたはカスタムフックの直下で呼ぶ
H-3 ● lint(一部) use で始まる名前の関数が、フックを正しく呼び出しているか フックを呼ばない単なる共通処理なら、通常の命名(get〜 等)にする

3-3. Refの扱い(R)

個人的に一番盲点だったのが R-1 です。「最新のコールバック関数をRefに入れておく」という頻出パターンも、描画処理の最中に ref.current = fn と書くと厳密にはルール違反になります。

ID 観点 改善案の目安
R-1 ● lint 描画中に ref.current の読み書きを行っていないか 表示用ならStateを使い、代入はEffect内で行う(Effect用途なら useEffectEvent を検討)
R-2 ○ lint(一部) 画面表示に関わる値をRefに、逆に描画に関係ない値をStateに入れていないか 描画をトリガーしたい値はState、保持するだけの値はRefに使い分ける
R-3 ○ Reactが生成したDOM要素を直接書き換えていないか 手動のDOM操作はフォーカスやスクロール、サイズ計測などの非破壊的操作に留める

3-4. 副作用・Effect(E)

Effectは「外部システム(ブラウザAPIやネットワーク等)とReactの状態を同期させる」ための機能です。ユーザー操作への応答(クリックなど)をEffectで処理しようとすると、状態の二重更新やコードの複雑化につながりやすい傾向があります。

Effectのsetupとcleanupのタイミング

処理をどこに置くかの判定

ID 観点 改善案の目安
E-1 ● lint Effect内で参照しているリアクティブな値(Props/State)を依存配列に含めているか 依存を外したい場合は、配列をごまかさず処理の構造自体を見直す
E-2 ● lint useEffectEvent をEffect(または別のEffect Event)の外部から呼んでいないか イベントハンドラから呼ぶべき処理は通常の関数として定義する
E-3 ○ 外部との同期ではない処理(データ加工など)にEffectを使っていないか 計算で出せる値は描画中に計算し、操作由来の処理はハンドラに書く
E-4 ○ ボタンクリック等の操作をきっかけとする処理をEffectで監視していないか ハンドラ側で明示的に実行する
E-5 ○ 子コンポーネントがEffect経由で親に状態変更を通知していないか ハンドラ内で親の通知関数を呼ぶか、状態管理の配置を見直す
E-6 ○ State更新が連鎖するようなEffectチェーンを作っていないか イベントハンドラ側で次の状態をまとめて計算する構成を検討する
E-7 ○ 毎描画で再生成されるオブジェクトや関数を安易に依存配列に入れていないか Effect内部で定義するか、プリミティブな値を取り出して依存配列に渡す
E-8 ○ 「Effectを発火させたくない」という理由で、描画中にRefへ代入して逃げていないか useEffectEvent を用いるか、関数の参照を安定させて依存配列に含める
E-9 ○ クリーンアップ関数を正しく実装し、開発時のStrictMode(二重実行)に耐えうるか リスナー解除や接続切断の片付け処理を対で記述する
E-10 ○ 非同期データ取得で、競合状態(古いリクエストが遅れて上書きする現象)を考慮しているか クリーンアップ用のフラグや AbortController で古い応答を破棄する
E-11 ○ 「1回だけ走らせる」ためのRefフラグ(didRunRef など)で、開発時の二重実行を握り潰していないか クリーンアップを正しく実装するか、アプリ全体で1回の処理ならモジュール直下に逃がす
E-12 ○ lint Effectの先頭で同期的・無条件に setState を呼んでいないか 描画中の計算で代替するか、コンポーネントの key 属性を変えて再マウントさせる
E-13 ○ useLayoutEffect の使用箇所が、画面のちらつき防止やレイアウト計測に限定されているか パフォーマンス低下を防ぐため、原則は通常の useEffect を優先する

3-5. 状態とイベント(S)

「Stateを更新した直後の行で、そのStateの新しい値を参照しようとして動かない」といったミスは、Stateがその描画回におけるスナップショットであることを意識すると防ぎやすくなります。

ID 観点 改善案の目安
S-1 ● setState 直後に該当Stateを読み出し、最新値が得られると期待していないか 更新後の値をローカル変数に保持して再利用する
S-2 ● 配列描画の key にインデックスや Math.random() などの不安定な値を使っていないか データ固有の一意なIDを使用する
S-3 ● イベントハンドラに「関数の実行結果」を直接渡していないか(onClick={fn()} など) onClick={() => fn(id)} のように関数定義を渡す
S-4 ● && 演算子の左辺が数値(0 など)になり、画面に「0」と描画されてしまっていないか count > 0 && ... のように明示的な真偽値へ変換する
S-5 ○ lint(一部) 既存のPropsやStateから計算可能な値を、わざわざ別のStateとして保持していないか 描画中の計算で導出する(負荷が大きい場合のみ useMemo を検討)
S-6 ○ 変更に追従させる意図で、Propsの値をそのまま初期Stateにコピーしていないか 原則Propsを直接参照する。意図的な初期値なら initialValue 等に改名する
S-7 ○ 状態の不整合が起きる真偽値フラグの組み合わせ(isLoading と isError が同時にtrueなど)を作っていないか 'loading' | 'error' | 'success' のようなステータス文字列で一元化する
S-8 ○ 常にセットで更新される複数のStateがバラバラに散らばっていないか 単一のオブジェクトにまとめるか、useReducer の採用を考える
S-9 ○ 配列の選択状態などで、要素全体を重複して保持していないか 選択中の id だけを保持し、要素自体は描画中に検索する構成にする
S-10 ○ 同じ情報を別々のコンポーネントで二重管理していないか 共通の親コンポーネントに状態を持ち上げる(Lifting State Up)
S-11 ○ 親のProps変更時に全Stateをリセットする処理を、Effectで行っていないか 対象コンポーネントに異なる key を指定してきれいに作り直す
S-12 ○ 前回のStateに依存する更新で、更新関数形式を使っていないケースがないか setCount(prev => prev + 1) の形式を使って安全に更新する
S-13 ○ 状態更新の分岐やパターンが多くなったとき、useReducer への移行を検討したか 複雑な遷移ロジックはReducerに切り出し、処理を純粋に保つ

3-6. カスタムフック(C)

カスタムフックで共有されるのは「処理のロジック」であって、「Stateの実体」そのものではない点に注意が必要です。

ID 観点 改善案の目安
C-1 ○ 単にフックをまとめただけの汎用ラッパー(useMount 等)になっていないか useOnlineStatus のように具体的で関心の明確な命名・設計にする
C-2 ○ 呼び出し側ごとに独立したStateが作られる挙動を理解して使っているか 複数箇所で同じ状態値を共有したいなら、StateのリフトアップやContextを検討する
C-3 ○ 呼び出し側がEffectの依存配列に指定する可能性のあるコールバックを、安定して返せているか 必要に応じてフック内部で useCallback でラップしておく

3-7. Propsとコンポーネント合成(K)

Propsのバケツリレーが深くなってきたときは、安易にグローバル状態へ逃げる前に「コンポーネント合成(JSXを直接渡す)」で解消できないか検討するのがおすすめです。

ID 観点 改善案の目安
K-1 ○ 使わないPropsを何階層も素通し(バケツリレー)していないか children などの合成パターンを使う。それでも深すぎる場合はContextを検討
K-2 ○ {...props} のスプレッド展開で、不要な属性まで下位DOMに流していないか コンポーネント側で必要なPropsを明示的に分割代入して渡す
K-3 ○ コンポーネント内部で null を返して非表示にする設計を多用しすぎていないか 出し分けの条件判断は、極力呼び出し元側に寄せる
K-4 ○ ハンドラの命名が標準的な慣例(受け渡しは onXxx、内部実装は handleXxx)に沿っているか 役割が直感的に伝わる命名に揃える
K-5 ○ Context を導入する前に、Propsの受け渡しや合成パターンで十分でないか検証したか まずはPropsの受け渡しや children で足りるかを確かめる
K-6 ○ React 19の新しい書き方に沿っているか forwardRef を使わずにPropsとして ref を受け取り、Providerとして <Context> を使う

3-8. テスト(T)

テストが通っていてもコンソールに警告が出ている場合は、状態更新のタイミングが制御しきれていないサインかもしれません。

ID 観点 改善案の目安
T-1 ● テスト実行時に "not wrapped in act(...)" の警告が出ていないか Testing Library の待機ヘルパーに置き換えるか、非同期の await act(async () => ...) で囲む
T-2 ○ act の呼び出しを await act(async () => ...) の非同期形式で書いているか 将来のバージョンアップに備え、同期形式の直接呼び出しを避ける
T-3 ○ StrictMode による開発時の二重実行でもテストがパスすることを確認しているか テストケースのルートを <StrictMode> で囲んで耐性を検証する
T-4 ○ コンポーネント自体を過度にモックせず、サーバー応答のモックを中心にできているか テスト用のモックはサーバー応答に寄せる(公式は、可能ならE2Eテストも勧めている)

4. 実際の変更差分にチェックリストを当ててみた結果

非同期でデータを先読みするカスタムフックと、それを使う画面コンポーネントの実装差分に対して、このチェックリストを実際に当ててみました。

  • 明確な違反: 2件
  • 推奨パターンとの乖離: 11件
  • 意図的な乖離(理由あり): 3件

検出された違反の2件は「描画中のRef代入(R-1)」と「テスト実行時のact警告(T-1)」でした。どちらも単体テスト自体は緑色でパスしていたため、目視や公式の観点がないとそのまま見逃していた可能性が高いと感じます。

4-1. 指摘を反映して実感したこと

指摘を反映したところ、Effect と State の数が減り、処理の置き場所がはっきりしました。

観点 反映前 反映後 変わったこと
画面コンポーネントの useEffect 4 2 「選択のリセット」と「親への通知」を Effect でしなくなった(E-5・S-11)
画面コンポーネントの useState 4 3 親が持っていた写しの State をなくした(S-10)
小さなカスタムフックの useState 2 1 いつも一緒に変わる2つを1つにまとめた(S-8)
先読み用フックの useRef 3 2 描画中に代入していた Ref をなくした(R-1)
テスト実行時の act の警告 6件 0件 テストランナー独自の待ちを Testing Library の waitFor に替えた(T-1)

ただし、行数そのものは減っていません。先読み用のフックは、どのデータに対する結果かを判別する型とコメントを足したので、3割ほど増えました。それでも Effect の中身が「取得を始めるだけ」になり、どこで何が決まるかを追いやすくなったと感じています。

保守性の面でも、次の変化がありました。

  • 判断を小さく試せるようになった: 画面に何を表示するかの判断を、React に依存しない純粋な関数に切り出し、親と子の両方で使う形にしました。この判断だけを小さなテストで確かめられます
  • 気づいていなかった不具合が直った: Ref に隠れて依存配列に現れていなかった値の変化に追従できていなかった点と、表示対象を切り替えた直後の1回の描画で前の状態が残る点が、この見直しで解消しました

5. やってみて感じたメリットと今後の課題

良かった点

  • 指摘にドキュメントの節名が添えられる安心感: 「公式のここにこう書いてあるので〜」とリンク付きで伝えられるため、個人の好みの押し付けにならず、心理的負担がかなり減りました。
  • 仕組みベースの理解が深まる: 「なぜEffectを使ってはいけないのか」「なぜRefを描画中に触ってはいけないのか」をライフサイクルの観点から振り返る良いきっかけになりました。

注意点・残る限界

  • バージョンの追従が必要: このリストは React 19 系(執筆時点)を前提に作成しています。フレームワークの仕様更新に伴ってベストプラクティスも変化するため、定期的な見直しは欠かせないと感じています。

6. まとめ

コードレビューはどうしても「過去に見かけた書き方」や「個人のコーディングスタイル」に引っ張られやすい領域です。

一次情報である公式ドキュメントをベースにルールを言語化しておくと、レビューイも納得感を持って修正できますし、チーム全体の設計力向上にもつながりやすいと感じました。レビューの観点に迷っている方の参考になれば幸いです!

参考資料

本記事の内容は、以下の公式情報で確認しました(2026年10月22日時点)。


Claudeならクラスメソッドにお任せください

クラスメソッドは、Anthropic社とリセラー契約を締結しています。各種製品ガイドから、業種別の活用法、フェーズごとのお悩み解決などサービス支援ページにまとめております。まずはご覧いただき、お気軽にご相談ください。

サービス詳細を見る

この記事をシェアする

AI白書

関連記事