mcpField
R
react-component-performance

react-component-performance

github.com/dimillian開発4.0k1.1k 回インストール30 週間前に更新
リポジトリ

react-component-performance について

React 開発者向けに、UI の動作を変えずにコンポーネントの描画遅延を特定し、最適化するスキルです。状態の分離やメモ化を行い、React DevTools Profiler で効果を検証します。

主な機能

  1. 01描画の要因とホットスポットの特定
  2. 02頻繁に変わる状態の分離
  3. 03props とコールバックの安定化
  4. 04計算量とリスト描画数の削減
  5. 05プロファイル記録の比較

活用シーン

  1. 01React の操作遅延の調査
  2. 02タイマー更新による大規模リストの再描画防止
  3. 03props が安定した行コンポーネントの最適化
  4. 04ベースラインとの比較による効果検証

インストール

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

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

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

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

詳細

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

概要

レンダーのホットスポットを特定し、コストの高い更新を切り分け、UI の動作を変えずに的を絞った最適化を適用します。

ワークフロー

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

チェックリスト

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

最適化パターン

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

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

// ❌ 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 を読み込みます。

コメント