0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

個人的アドカレAdvent Calendar 2024

Day 20

React Profilerコンポーネントでレンダリング時間を計測してみる

Posted at

はじめに

本記事は、Profilerを触ってみたものを備忘録としてまとめたものになります。React Profilerコンポーネントを使って対象のコンポーネントのパフォーマンス情報を取得する処理を実装をしていきます。

Profiler

React の Profiler は、コンポーネントのパフォーマンスを測定できる便利なツールです。
Profilerを使用した簡単なコンポーネントを作ってみます。

import { Profiler } from 'react';

function SampleComponent() {
  const onRenderCallback = (
    id,             // 測定対象のコンポーネントを識別するための一意の名前
    phase,          // "mount" か "update"
    actualDuration  // レンダリングにかかった時間
  ) => {
    console.log(`${id}${phase}にかかった時間: ${actualDuration}ms`);
  };

  return (
    <Profiler id="SampleComponent" onRender={onRenderCallback}>
      {/* 測定したいコンポーネントをここに */}
    </Profiler>
  );
}

上記の場合取得できる情報は次の通りです。

  • id:対象のコンポーネントを一意に識別するID
  • phase: "mount"(初回レンダリング)か"update"(再レンダリング)
  • actualDuration: レンダリングにかかった時間(ミリ秒)

コンポーネントのパフォーマンスを計測してみる

意図的に重い処理を含むコンポーネントを作成し、Profilerでパフォーマンスを計測してみます。

import { Profiler, useState } from 'react';

// サンプルデータ用の配列
const sampleFoods = ['寿司', 'ラーメン', 'カレー', 'ピザ', '天ぷら'];
const sampleSports = ['サッカー', '野球', 'バスケ', 'テニス', '水泳'];

// サンプルデータ生成
const generateItems = (count) => Array.from({ length: count }, (_, i) => ({
  id: Math.random().toString() + `_${i}`,
  firstName: `名前${i}`,
  lastName: `苗字${i}`,
  favoriteFood: sampleFoods[i % sampleFoods.length],
  favoriteSport: sampleSports[i % sampleSports.length],
  email: `email${i}@example.com`
}));

// 重い処理のシミュレート用関数
const heavyProcess = (text) => {
  let sum = 0;
  for (let i = 0; i < 1000000; i++) {
    sum += i;
  }
  const [displayText] = [`${text}`, sum];
  return displayText;
};

function SampleList({ items }) {
  const processedItems = items.map(item => ({
    ...item,
    displayName: heavyProcess(`${item.firstName} ${item.lastName}`),
    interests: heavyProcess(`好きな食べ物: ${item.favoriteFood}、好きなスポーツ: ${item.favoriteSport}`),
  }));

  // レンダリング時の処理時間を表示
  const onRenderCallback = (id, phase, actualDuration) => {
    console.log(`${id}${phase}フェーズ: ${actualDuration.toFixed(1)}ms`);
  };

  return (
    <Profiler id="SampleList" onRender={onRenderCallback}>
      <div className="list">
        {processedItems.map(item => (
          <div key={item.id} className="item">
            <h3>{item.displayName}</h3>
            <p>{item.interests}</p>
            <p>{item.email}</p>
          </div>
        ))}
      </div>
    </Profiler>
  );
}

export default function App() {
  const [items] = useState(() => generateItems(200));
  return <SampleList items={items} />;
}

上記のソースでサーバを立ち上げて、初回レンダリングと再レンダリングを実行してみます。
ブラウザの開発者ツールから確認したログは下記の通りです。

出力ログ
SampleListのmountフェーズ: 6.3ms
SampleListのupdateフェーズ: 2.9ms

Profilerを使うことで、mountフェーズ(初回レンダリング)とupdateフェーズ(再レンダリング)の処理時間が計測できました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?