mcpField
R
react-component-performance

react-component-performance

github.com/shipshitdev開発3988 回インストール1 日前に更新
リポジトリ

react-component-performance について

遅いコンポーネントの原因特定や不要な再レンダリングの削減を支援する、React 開発者向けのパフォーマンススキルです。最適化パターンを提示し、React DevTools Profiler で基準記録と比較して検証します。

主な機能

  1. 01再レンダリング要因とホットスポットの特定
  2. 02頻繁に変わる状態の分離
  3. 03プロパティとコールバックの安定化
  4. 04計算処理とリスト描画の削減
  5. 05最適化前後のプロファイル比較

活用シーン

  1. 01遅い React コンポーネントの診断
  2. 02リスト内の再レンダリング削減
  3. 03プロファイリングによる最適化の検証

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/shipshitdev/skills --skill react-component-performance

インストール後、Claude Code で/react-component-performanceを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

plugin.json
README.md
agents/
openai.yaml
references/
examples.md

詳細

React コンポーネントのパフォーマンス

レンダリングのボトルネックを特定し、負荷の高い更新を切り分け、UI の動作を変えずに的を絞った最適化を適用します。

使用するタイミング

  • ユーザーから、React コンポーネントのプロファイリングやパフォーマンス改善を求められた場合。
  • React UI で再レンダリング、リストの遅延、または負荷の高いレンダリング処理を減らす必要がある場合。

API のレイテンシ、データベースクエリ、キャッシュ、バックグラウンドジョブ、インフラの チューニングには、代わりに performance-expert を使用してください。

ワークフロー

  1. 遅延を再現するか、内容を説明します。
  2. 再レンダリングを引き起こす要因(state の更新、props の頻繁な変更、effects)を特定します。
  3. 頻繁に変化する state を負荷の高いサブツリーから切り離します。
  4. props とハンドラーを安定させ、効果が見込める箇所をメモ化します。
  5. 負荷の高い処理(計算、DOM サイズ、リストの長さ)を減らします。
  6. 検証:React DevTools Profiler を開き、操作を記録し、Flamegraph で約 16 ms を超えてレンダリングされるコンポーネントを確認します。最適化前に記録したベースラインと比較します。

チェックリスト

  • 計測:React DevTools Profiler を使用するか、レンダリングをログに記録して、ベースラインを取得します。
  • 頻繁な更新を特定:タイマー、スクロール、入力、アニメーションで更新される state を特定します。
  • 分割:更新頻度の高い state を子コンポーネントに移し、負荷の高いリストを静的に保ちます。
  • メモ化:props が安定している場合に限り、リーフ行を memo でラップします。
  • props を安定化:ハンドラーや派生値に useCallback/useMemo を使用します。
  • レンダリング中の派生処理を避ける:事前に計算するか、メモ化したヘルパー内で計算します。
  • リストのサイズを制御:長いリストにはウィンドウ化/仮想化を使用し、非表示の項目はレンダリングしないようにします。
  • キー:キーが安定していることを確認します。順序が変わる可能性がある場合はインデックスを避けます。
  • Effects:依存配列を確認し、レンダリングのたびに再実行される effects を避けます。
  • スタイル/レイアウト:負荷の高いレイアウトの頻繁な再計算や、大きな Markdown/diff のレンダリングに注意します。

最適化パターン

頻繁に更新される state を切り離す

タイマーやアニメーションのカウンターを子コンポーネントに移し、親のリストが更新のたびに再レンダリングされないようにします。

// ❌ Before – entire parent (and list) re-renders every second
function Dashboard({ items }: { items: Item[] }) {
  const [tick, setTick] = useState(0);
  useEffect(() => {
    const id = setInterval(() => setTick(t => t + 1), 1000);
    return () => clearInterval(id);
  }, []);
  return (
    <>
      <Clock tick={tick} />
      <ExpensiveList items={items} /> {/* re-renders every second */}
    </>
  );
}

// ✅ After – only <Clock> re-renders; list is untouched
function Clock() {
  const [tick, setTick] = useState(0);
  useEffect(() => {
    const id = setInterval(() => setTick(t => t + 1), 1000);
    return () => clearInterval(id);
  }, []);
  return <span>{tick}s</span>;
}

function Dashboard({ items }: { items: Item[] }) {
  return (
    <>
      <Clock />
      <ExpensiveList items={items} />
    </>
  );
}
useCallback と memo でコールバックを安定化する
// ❌ Before – new handler reference on every render busts Row memo
function List({ items }: { items: Item[] }) {
  const handleClick = (id: string) => console.log(id); // new ref each render
  return items.map(item => <Row key={item.id} item={item} onClick={handleClick} />);
}

// ✅ After – stable handler; Row only re-renders when its own item changes
const Row = memo(({ item, onClick }: RowProps) => (
  <li onClick={() => onClick(item.id)}>{item.name}</li>
));

function List({ items }: { items: Item[] }) {
  const handleClick = useCallback((id: string) => console.log(id), []);
  return items.map(item => <Row key={item.id} item={item} onClick={handleClick} />);
}
派生データはレンダリングの外で処理する
// ❌ Before – recomputes on every render
function Summary({ orders }: { orders: Order[] }) {
  const total = orders.reduce((sum, o) => sum + o.amount, 0); // runs every render
  return <p>Total: {total}</p>;
}

// ✅ After – recomputes only when orders changes
function Summary({ orders }: { orders: Order[] }) {
  const total = useMemo(() => orders.reduce((sum, o) => sum + o.amount, 0), [orders]);
  return <p>Total: {total}</p>;
}
その他のパターン
  • 行を分割する:リストの行を、props を絞ったメモ化コンポーネントとして切り出します。
  • 負荷の高いレンダリングを遅らせる:負荷の高いコンテンツは、展開されるまで遅延レンダリングするか折りたたんでおきます。

プロファイリングの検証手順

  1. React DevTools → Profiler タブを開きます。
  2. Record をクリックし、遅い操作を行ってから Stop をクリックします。
  3. Flamegraph ビューに切り替えます。コンポーネント名と約 16 ms を超える時間が表示されたバーが、最適化候補です。
  4. Ranked chart を使って自己レンダリング時間で並べ替え、上位の問題箇所を対象にします。
  5. 一度に 1 つの最適化を適用し、再度記録して、レンダリング回数と所要時間をベースラインと比較します。

参考例

ユーザーが具体的なリファクタリング例を求めている場合は、references/examples.md を読み込みます。

コメント