mcpField
R
react-component-performance

react-component-performance

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

react-component-performance について

UIの動作を変えずに、Reactコンポーネントのパフォーマンスを調査・改善するスキルです。プロファイリング、的を絞ったレンダリング最適化、ベースラインとの比較による検証を案内します。

主な機能

  1. 01レンダリングのボトルネック特定
  2. 02不要な再レンダリングの削減
  3. 03頻繁に変化する状態の分離
  4. 04propsとハンドラーの安定化
  5. 05高コストな描画とリストの最適化
  6. 06React DevTools Profilerで検証

活用シーン

  1. 01遅いReactコンポーネントの調査
  2. 02長いリストの遅延軽減
  3. 03高コストなUI操作のプロファイリング

インストール

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

$npx skills add https://github.com/sickn33/agentic-awesome-skills --skill react-component-performance

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

同梱ファイルagents/openai.yamlreferences/examples.md

詳細

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

概要

レンダリングのホットスポットを特定し、高コストな更新を分離し、UI の挙動を変えずに狙いを定めた最適化を適用します。

使用する場面

  • ユーザーが遅い React コンポーネントのプロファイリングや改善を依頼したとき。
  • React UI における再レンダリング、リストの遅延、高コストなレンダリング処理を削減する必要があるとき。

ワークフロー

  1. 速度低下を再現するか、説明します。
  2. 何が再レンダリングを引き起こすか(state の更新、props の変動、effect)を特定します。
  3. 頻繁に変化する state を重いサブツリーから分離します。
  4. props とハンドラーを安定化させ、効果がある箇所でメモ化します。
  5. 高コストな処理(計算、DOM サイズ、リストの長さ)を削減します。
  6. 検証: React DevTools Profiler を開く → 操作を記録する → Flamegraph で約 16 ms を超えてレンダリングしているコンポーネントを調べる → 最適化前のベースライン記録と比較します。

チェックリスト

  • 測定: React DevTools Profiler を使うかレンダリングをログに記録し、ベースラインを取得します。
  • 変動の特定: タイマー、スクロール、入力、アニメーションで更新される state を特定します。
  • 分割: 刻々と変化する state を子コンポーネントに移し、重いリストは静的なままにします。
  • メモ化: props が安定している場合にのみ、末端の行を memo でラップします。
  • props の安定化: ハンドラーと派生値に useCallback/useMemo を使います。
  • レンダリング内の派生処理を避ける: 事前計算するか、メモ化したヘルパー内で計算します。
  • リストサイズの制御: 長いリストはウィンドウ化/仮想化し、非表示の項目をレンダリングしないようにします。
  • キー: 安定したキーを確保し、順序が変わりうる場合はインデックスを避けます。
  • effect: 依存配列を確認し、毎回のレンダリングで再実行される effect を避けます。
  • スタイル/レイアウト: 高コストなレイアウトスラッシングや、大きな 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; memo can skip parent-driven re-renders when props compare equal; state/context can still re-render Row
const Row = memo(({ item, onClick }: RowProps) => (
  <li><button type="button" onClick={() => onClick(item.id)}>{item.name}</button></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 を読み込みます。

制限事項

  • このスキルは、タスクが上記のスコープに明確に一致する場合にのみ使用してください。
  • 出力を、環境固有の検証、テスト、専門家によるレビューの代わりとして扱わないでください。
  • 必要な入力、権限、安全上の境界、成功基準が欠けている場合は、停止して確認を求めてください。

コメント