react-refactor-component · git:20260409.3c1ebaf · 2026-04-09 · sha256 eea05f7705286c3a

react-refactor-component git:20260409.3c1ebafA

Immutable. This exact content never changes and is served at /api/v1/blob/eea05f7705286c3a.

---
name: react-refactor-component
description: Refactor React components to follow project conventions. Use when reorganizing, splitting, or cleaning up existing React component files.
argument-hint: "[file-path or component-name]"
---

# Reactコンポーネントリファクタリング

指示されたReactコンポーネントを、本ドキュメントで定めるルールに沿ってリファクタリングします。

## 使い方

```text
/react-refactor-component <ファイルパス または コンポーネント名>
```

`$ARGUMENTS`で指定されたコンポーネントと、
その周辺で同じファイルに同居している関連コンポーネントを読み取り、
ルール違反を検出してリファクタリングを行います。
`$ARGUMENTS`が省略された場合は、
IDEで開いているファイル/ユーザーが直前に話題にしたコンポーネントを対象とします。

## リファクタリングの絶対ルール

以下のルールは交渉不可能です。リファクタリング後のコードは必ず全項目を満たしている必要があります。

### ファイル内の構造順序を守る

すべてのコンポーネントファイルは、上から順に次の流れで構成します。

1. デザイン定義 — `sva`/`cva`/`css`などのstyled-system呼び出し
2. props定義 — `type Props = ...`や`interface Props { ... }`
3. Functional Component定義 — `export const Foo: React.FC<Props> = ...`や`export function Foo(props: Props): React.ReactElement { ... }`

import群は当然この前に置きます。
純粋な振る舞いだけのコンポーネントならデザイン定義は省略可能ですが、
それ以外で順序の入れ替えは認めません。

理由: 「見た目」「インターフェース」「振る舞い」の責務分離をファイル内の縦方向で表現することで、
コンポーネントを読むときの認知の階段を一定に保つため。

### 1ファイル1コンポーネント

1つのファイルの中にexport/非exportを問わずコンポーネントを2つ以上書かないでください。

ファイル内で再利用される小さなコンポーネントが必要になった場合は、必ず別ファイルに切り出します。
切り出した先のファイル名はIDEのQuick Openで識別しやすい名前にし、
`index.tsx`や`index.ts`といった汎用名を新規作成しないでください。
既存の`index.tsx`を大幅に書き換える場合も、
リファクタリングの一環として適切なファイル名にリネームします。

例外として、他のコンポーネントのrender propに渡すためのごく小さなコンポーネントは、
その場で定義することを許容します。
`<DataGrid renderRow={...} />`や`columns[i].render`、
`react-hook-form`の`Controller`の`render`などが該当します。
ただし次の条件をすべて満たすこと。

- 呼び出し元のrender関数の引数型にそのまま当てはめられる、数行〜十数行程度の軽量なものに限る
- ファイル内で1度しか使われない。使い回される可能性が出てきた時点で別ファイルに切り出す
- どのrender propに渡すために定義しているのかを説明するコメントを直前に付ける

例:

```tsx
// DataGridのrenderRowに渡すための行コンポーネント。このファイル内でしか使わない
const DeviceRow: React.FC<{ device: Device }> = ({ device }) => (
  <tr>
    <td>{device.id}</td>
    <td>{device.name}</td>
  </tr>
);
```

ファイル内で複数回使う場合、それなりの行数がある場合、
呼び出し側から渡される関数でなく通常のJSXの一部として使っている場合などは、
必ず別ファイルに切り出してください。

### コンポーネントが肥大化してきたら分割する

「関数の始まりからJSXが登場するまでに30行程度かかっている」状態は、
コンポーネントが過剰な責務を持っている兆候です。
次のいずれかの方法で責務を逃します。

- ロジックをカスタムフックに切り出す。state、副作用、メモ化、ハンドラの寄せ集めはほぼ必ずフック化できます
- 表示の塊を子コンポーネントに切り出す
- 算出値をモジュールスコープの純粋関数に切り出す

ただし、JSX自体が長くなることは必ずしも悪ではありません。
判定すべきは「行数」ではなく「認知負荷」です。
次のような状態は危険信号として扱ってください。

- 同一の構造が縦に並んでいるが、わずかな差異があってループに落とせていない
- 条件分岐ごとにJSXの枝が派生しており、どの枝が描画されるかを脳内でトラッキングする必要がある
- 1つの要素のクラス名/propsを組み立てるために手前で何段ものローカル変数を準備している
- 同じblock内でユーザー情報・支払い情報・通知設定のように複数のドメイン概念を扱っている

逆に、整然と並んだ単純な要素列が長いだけであれば、無理に分割する必要はありません。
「他人がこのコンポーネントを上から下まで一気に読めるか」を基準にしてください。

## ワークフロー

### 対象を読む

`$ARGUMENTS`で指定されたコンポーネントファイルをReadで開きます。
ファイル名から責務がわからない場合は、import元の使用箇所もあわせて確認します。

### 違反項目を洗い出す

以下のチェックリストでコードを点検し、違反箇所を列挙します。

- [ ] 構造順序: import → デザイン定義 → props定義 → コンポーネントの順序になっているか
- [ ] 1ファイル1コンポーネント: ファイル内のコンポーネントは1つだけか
- [ ] 1ファイル1コンポーネント補足: 新規または大幅書き換え対象のファイル名が`index.tsx`/`index.ts`ではないか
- [ ] 肥大化: 関数の冒頭から最初のJSX、つまり`return`の直前までが肥大化していないか
- [ ] 肥大化: JSX内に重複する構造、深い条件分岐、外側の準備変数の多さなどの読みづらさが同居していないか

加えてweb-tasukeプラグインの他スキルで定義されているTypeScriptの規約にも違反していないか確認してください。

### 変更の見取り図をユーザーに提示する

リファクタリングを実行する前に、何をどう変更するつもりかを箇条書きで提示し、合意を取ります。
具体的には次を含めます。

- 切り出す予定のカスタムフック/子コンポーネントとそのファイル名
- 元ファイルの最終的な構成、デザイン定義・props・コンポーネントの配置
- リネームが発生する場合は旧ファイル名 → 新ファイル名のマッピング

フック名やファイル名の好み、分割粒度などユーザーの方針判断が必要な箇所があれば、
ここでAskUserQuestionを使って確認します。

### 段階的に編集する

合意が取れたらEdit/Writeでリファクタリングを行います。次の順序で進めると壊れにくいです。

1. カスタムフックや子コンポーネントなど切り出し先の新規ファイルを作成する
2. 元ファイルから切り出した実装を取り除き、新規ファイルからimportする
3. デザイン定義 → props → コンポーネントのファイル順序を整える
4. ファイル名のリネームが必要な場合は、それを最後に行い、import元をすべて更新する

### 検証

リファクタリング後、プロジェクトのリンターとビルドを実行して壊していないことを確認します。

エラーが出た場合は、原因を読み取った上で根本修正します。
`// eslint-disable-next-line`や`as any`での回避は禁止です。

### 報告

最後に、ユーザーへ次を簡潔に報告します。

- 検出した違反項目とその対応
- 新規作成/リネーム/削除されたファイル
- リンターとビルドの結果
- 動作確認が必要な箇所。
  リファクタリングなので振る舞いは変わらない想定だが、念のため確認してほしい点を伝える

## やってはいけないこと

- バグ修正・仕様変更・最適化など振る舞いの変更を伴うリファクタリングを、
  明示的な指示なしに混ぜ込まない
- いずれかのルールを「これは例外でOK」と独断で判断しない。
  どうしても例外にせざるを得ない場合は必ずユーザーに確認する
- 「将来こうなるかもしれないから」という理由で抽象化を増やさない。
  今ある具体に対して必要最低限の分割だけを行う
- `sva`やpanda CSSのトークンなど既存の命名規約・デザイントークンを勝手に変更しない
- 切り出した結果、importの循環参照やファイル間の責務の逆流が起きる構造にしない