公開日: 2025 年 10 月 14 日
Interaction to Next Paint(INP)は、応答性を測定するための重要なウェブに関する主な指標です。Fotocasa では、2024 年に INP が初回入力遅延(FID)に置き換わった際に、「改善が必要」と「不良」に移行したページが多数あることが Google Search Console で明らかになりました。このケーススタディでは、これらの問題を診断して解決するために使用されたツールと戦略について説明します。最終的に、INP は大幅に改善されました。
Fotocasa チームの出発点
FID から INP への移行前は、パソコンとモバイルの両方でほぼすべてのページが「良好」のしきい値内に収まっていました。つまり、当時のウェブに関する主な指標(LCP、CLS、FID)はすべて良好なパフォーマンスを示していました。しかし、INP に移行すると、ほとんどのページが「改善が必要」に移行し、一部のページは「不良」に移行しました。これは、ほとんどのユーザー操作で INP の値が 200 ミリ秒を超えたためです。
この変更により、Fotocasa チームはユーザー エクスペリエンスの重要な側面を見落としていたことに気づきました。FID は最初のインタラクションの遅延のみを測定しますが、INP はすべてのインタラクションの応答性を評価し、入力処理とプレゼンテーションの遅延を考慮します。この広範な測定は、真のインタラクティビティ(Google が述べているように)をはるかに適切に表すものであり、機会損失を明らかにしました。
Google Search Console ではフィールド パフォーマンス データが提供されますが、リアルタイムの分析情報は提供されません。データは 28 日間の期間で集計されるため、どのインタラクションが問題の原因となっているかを正確に特定することは困難です。
最も遅く、ユーザーが最も頻繁に使用するインタラクションを特定し、チームの開発環境で確実に再現するために、INP をリアルタイムで追跡する方法が必要でした。同様に重要なのは、どの修正が役に立ったかだけでなく、どの調整が意図せず事態を悪化させたかなど、変更の影響を把握することでした。
そのため、一連のツールを使用して、問題の診断と解決を行いました。最も重要なものは次のとおりです。
- Google Chrome DevTools(特に [パフォーマンス] タブ)。
- Fotocasa チームが Datadog で web-vitals ライブラリを使用して構築したカスタム RUM(実際のユーザー モニタリング)システム。
- React Developer Tools。
問題の診断に役立つツール
INP のパフォーマンスの問題を診断してデバッグするために、次のツールが使用されました。
Google Chrome DevTools
ウェブ アプリケーションでウェブに関する主な指標に関連する問題を検出して再現する優れた方法は、Google Chrome DevTools の [パフォーマンス] タブを使用することです。[パフォーマンス] タブでは、Core Web Vitals の指標が自動的に測定され、読み込み、インタラクティブ性、レイアウト シフトの指標に関するフィードバックが即座に提供されます。これらの指標が他の Google ツールに報告される方法とほぼ一致しています。
INP の問題を特定して解決するために、Fotocasa チームは通常、CPU をスロットリングして、ローエンド デバイスとミッドレンジ デバイスのパフォーマンスをシミュレートすることから始めました。これにより、Fotocasa チームはより制約の厳しい条件下でページがどのように動作するかを観察できるようになりました。次に、プロファイラを使用してセッションを記録し、ユーザー インタラクションに焦点を当ててトレースを慎重に分析し、パフォーマンスの問題を特定しました。
ボトルネックを特定する際は、INP のサブパートと、ブラウザが各サブパート内で実行するタスクを調べると特に効果的です。たとえば、次の画像では、ドキュメントの本文のスタイルの変更によって 2 回のスタイルの再計算が発生したため、INP がかなり高くなっています。
Fotocasa は、INP やその他のコア ウェブ バイタル指標を追跡するシステムをセットアップし、パフォーマンスの問題を迅速に特定して対処できるようにしました。指標が特定のしきい値(Google が定義した範囲に基づく)を超えると、アトリビューションが記録され、問題を分析して解決できるようになります。
このシステムでは、web-vitals ライブラリを使用して、Chrome で測定され、他の Google ツール(Chrome ユーザー エクスペリエンス レポート、Page Speed Insights、Search Console の速度レポートなど)に報告される方法と正確に一致する方法で、実際のユーザーからこれらの指標を取得しました。
包括的なビューと一元的な追跡を実現するため、Fotocasa は Datadog を使用してデータを収集、可視化し、チームが情報に基づいたデータドリブンな意思決定を行えるようにしました。カスタム指標を使用することで、費用対効果を維持しつつ、Fotocasa ウェブサイトのほぼすべてのユーザーをより正確にトラッキングできるようになりました。
このシステムにより、Fotocase チームは、変更が指標に影響するかどうか、予期しない変更が発生して指標が損なわれる可能性があるかどうかを迅速にモニタリングできます。INP 指標は、入力遅延、処理時間、表示遅延などの部分に分解して、インタラクションのどの部分がインタラクション時間の長さに主に影響しているかを正確に特定できます。
Fotocasa は、図 7 と図 8 に示すような異常を検出すると、直ちに対応し、OpenSearch を使用して、変更が発生している可能性のある場所を特定しました。web-vitals ライブラリから提供されたデータは、ターゲット(指標値の上昇の原因となっている可能性のある DOM 要素)の特定に役立ち、チームが問題の修正に集中するのに役立ちました。
さらに、ページタイプ、デバイス、読み込み状態などのさまざまなフィルタを定義してシナリオを絞り込み、INP がどのように影響を受けているかをより正確に把握できます。
React Developer Tools
React Developer Tools を使用して Fotocasa のデバッグ機能を強化しました。このツールには、再レンダリングされたコンポーネントを視覚的にハイライト表示できる強力な機能があります。
この機能は、[Profiler] タブに移動して有効にできます。そこから、上部のバーの右側にある歯車アイコンをクリックし、[全般] タブに移動して、[コンポーネントのレンダリング時に更新をハイライト表示する] チェックボックスをオンにします。この機能を有効にすると、コンポーネントが再レンダリングされるときにハイライト表示され、動的な視覚表現が提供されます。
再レンダリングの原因を特定する
再レンダリングされたコンポーネントが特定されたら、次の質問は「なぜ再レンダリングされたのか」です。React DevTools は、フレーム グラフ ビューの便利なツールチップでこの質問に答えます。
この情報にアクセスするには、プロファイラ セッションを記録します。プロファイラの出力を分析すると、次のような有用な情報が得られます。
- 右上には、React のコミット数が表示されます。
- フレームグラフはコンポーネント ツリーを視覚的に表したもので、グレーは再レンダリングされなかったコンポーネントを示しています。各バーは、React コンポーネント ツリーが変更されたときと、対応する変更が DOM にコミットされたときを表します。
- フレーム グラフの各コンポーネントにカーソルを合わせると、その再レンダリングの理由が [Why did this render?](なぜこのレンダリングが行われたのか)という小見出しの下に表示されます。
コンポーネントの再レンダリングの理由としては、次のようなものが考えられます。
- コンポーネントが初めてレンダリングされたかどうか
- コンテキストが変更されました
- フックが変更されました
- Props が変更された
- [都道府県] が変更されました
- 親コンポーネントがレンダリングされた
レンダリング時間を調べる
フレームグラフの色は、意味のある情報を伝えます。さまざまな青の色合いは、他のコンポーネントと比較して、コンポーネントのレンダリング時間が比較的短いことを示します。逆に、オレンジや赤などの色は、コンポーネントのレンダリングに時間がかかったことを示します。
Fotocasa チームが問題を解決した方法
不要な再レンダリングを削除する
再レンダリングは、React が新しいデータで UI を更新する必要があるたびに発生します。通常、これはユーザー操作、API レスポンス、またはユーザー インターフェースの更新を必要とするその他の重要なイベントから発生します。再レンダリングごとに JavaScript が実行されるため、特に大きなコンポーネント ツリーで再レンダリングが一度に多数実行されると、メインスレッドがブロックされ、パフォーマンスの問題が発生する可能性があります。
再レンダリングには次の 2 種類があります。
- 必要な再レンダリング: コンポーネントが新しいデータを所有または使用しているため、更新が必要な場合。
- 不要な再レンダリング: 効率の悪い状態管理や不適切なプロパティ処理が原因で、コンポーネントが意味のある変更なしに更新される場合。
不要な再レンダリングが数回発生しても、React は十分に高速であるため、通常はユーザーが気づくことはありません。ただし、頻繁に発生したり、コンポーネント ツリーの深いところで発生したりすると、ユーザー エクスペリエンスが損なわれ、ページの INP に悪影響が及ぶ可能性があります。
Fotocasa チームも同様でした。ウェブサイトで不要な再レンダリングが多数発生していることに気づきました。これらの問題は、主に次の 2 つのシナリオで発生しました。
- ページの読み込み中: メインスレッドでの長時間タスクの数が増加し、初回操作が遅延したため、ページの INP に悪影響を及ぼしました。
- ユーザー インタラクション中: ほとんどのインタラクションの処理時間を増やし、INP も悪化させました。
Fotocasa のウェブサイトでは、不要な再レンダリングが多数最適化されました。特に大きな最適化が実現したのは検索ページです。ページの読み込み時に不要な再レンダリングが 3 回発生していました。これらを削除したところ、次の結果が得られました。
- 長いタスクの数が少ない(次の図を参照)
- Total Blocking Time の短縮(図 14 と図 15 を比較)
状態のコロケーション
React の状態を適切に配置しないと、アプリケーションの速度が低下し、UI の応答が遅くなることがあります。コンポーネントの状態が変化すると、エスケープ ハッチ(メモなど)が使用されない限り、その子コンポーネントはデフォルトで再レンダリングされます。
前のセクションで説明したように、再レンダリング自体は悪いことではありませんが、特定の状態更新によってページ全体が再レンダリングされると、レンダリング後に DOM の更新が行われるため、インタラクションが遅くなる可能性があります。
たとえば、検索ページには、ボタンをクリックするとすべてのフィルタが表示されるダイアログがあります。
この場合、ダイアログの開閉状態を制御する状態は検索ページに配置されました。この状態が変更されると、ページ全体が再レンダリングされ、INP が悪化していました。特に、DevTools で CPU スロットリングを使用した場合に、低速のデバイスでこの現象が顕著でした。
変更をトリガーするコンポーネントにできるだけ近い状態で状態を変更すると、この問題は解決します。この場合、状態をフィルタのボタン コンポーネントに配置して、状態が変化したときにボタンのみが再レンダリングされるようにします。
不要な状態を削除する
状態に冗長な情報や重複する情報を含めるべきではありません。そうすると、不要な再レンダリングが発生し、問題が生じる可能性があります。
たとえば、Fotocasa のフィルタバーには、特定の検索に適用されたフィルタの数を表すテキストが表示されます。
適用されたフィルタの数は、アプリの状態から計算されます。しかし、これによりコンポーネント全体が不必要に再レンダリングされるだけでなく、このコンポーネントはサーバーサイドでレンダリングされるため、レイアウト シフトが発生することもありました。
const [filtersCount, setFiltersCount] = useState(DEFAULT_COUNTER)
useEffect(() => {
const counter = filters
? Object.keys(filters)
?.reduce(reducerCounter, [])
?.filter((param) => searchParams?.[param]).length
: DEFAULT_COUNTER
setFiltersCount(counter)
}, [searchParams]);
この問題を解決するため、状態を使用する代わりに、変数を使用してフィルタ オブジェクトから値を取得しました。
const counter = filters
? Object.keys(filters)
?.reduce(reducerCounter, [])
?.filter((param) => searchParams?.[param]).length
: DEFAULT_COUNTER;
コストのかかるレンダリングを減らす
React アプリケーションでインタラクションが発生すると、通常は状態の変更がトリガーされます。前述のとおり、コンポーネントの状態が変化すると、そのコンポーネントとそのすべての子が再レンダリングされます。
これらのコンポーネントのレンダリング関数のいずれかが遅いと、長いタスクが生成され、DOM の更新に時間がかかるため、ページの INP に悪影響を及ぼします。
Fotocasa チームは、コンポーネントのレンダリング関数内の時間のかかる計算をできるだけ最小限に抑えようとしました。Chrome DevTools と React Developer Tools は、レンダリングの遅いオペレーションを検出するのに非常に役立ちました。
コードの実行を遅延させる
コンポーネントのレンダリング関数の最適化に加えて、他の関数も最適化され、長いタスクが可能な限り最小限に抑えられました。ただし、一部のタスクはサードパーティのコードに依存しているため、最適化できませんでした。
たとえば、分析です。この場合、ユーザー操作が発生したときに分析コードの実行を遅らせ、DOM の更新を優先することにしました。これを実現するため、Fotocasa チームは idlefy というライブラリを使用しました。これにより、ブラウザがすぐに閉じられた場合でも、分析コードが実行されることが保証されました。
パフォーマンス文化
パフォーマンスの改善は 1 回限りの取り組みではなく、本番環境にリリースされるすべての機能で考慮する必要があります。チームの全員が足並みを揃える必要があります。そうしないと、Core Web Vitals の回帰はほぼ避けられません。
この問題を解決するため、Fotocasa チームはチーム内で積極的に知識を共有し、Fotocasa の Datadog RUM データに基づいてパフォーマンスの問題を特定するための明確なフレームワーク(問題の再現方法など)を確立しました。RUM システムで Core Web Vitals(特に INP)のアラートを設定し、Slack で Fotocasa チームに直接通知するように構成しました。このアプローチにより、パフォーマンスを常に意識し、問題が回帰になる前に検出することができました。
結果
Fotocasa で INP を改善するには、技術的な最適化と文化的な変化を組み合わせる必要がありました。不要な再レンダリングを排除し、状態の配置を最適化し、コストのかかるレンダリングを削減し、重要でないコードを遅延させることで、Fotocasa チームはすべてのパソコン用ページを「改善が必要」から「良好」に移行し、モバイル用ページを大幅に改善しました。ほぼすべての「不良」と「改善が必要」なページを「良好」にアップグレードしました。
これらの変更により、Fotocasa のユーザー エクスペリエンス全体が向上し、他の取り組みと合わせて、問い合わせと電話のリード広告が 27% 増加しました。これにより、同社の主要なビジネス指標が直接的に強化されました。
Datadog によるリアルタイム モニタリングにより、Fotocasa チームは INP の改善を検証し、異常を迅速に検出し、回帰を防ぐことができました。これらの成果に加えて、Fotocasa はウェブ パフォーマンスを開発文化に組み込むことにも成功し、INP と Core Web Vitals がすべてのリリースで優先事項として扱われるようにしました。