見出し画像

学生管理ページ(React)のパフォーマンス改善

こんにちは、HRクラウドの採用一括かんりくんdevopsチームです。
私たちは、優れたユーザーエクスペリエンスの提供を目指し、継続的なパフォーマンス改善に取り組んでいます。本記事では、学生管理ページのロード時間とデータ転送量を改善した取り組みを紹介します。


改善の背景と目的

学生管理ページは、当社Saasサービスの核心機能の一つであり、ユーザーが最も頻繁に利用するページの一つです。
このページは、大量のデータと複雑なインタラクションを備えたUIコンポーネントを多く持つため、Core Web Vitalsで定義されているLCP, INP指標値の低いアクティビティを観測することがしばしばありました。余談ですが、パフォーマンスモニタリングにはNew Relicを用いています。
どんなUIを備えているかは、同等の機能を提供する候補者ページの改善(第一弾)記事で紹介してますので、そちらをご参照ください。
今回は、特にLCPの改善に焦点を当て、次の2つを目的に設定しました:

  • ページロード時間の短縮

  • データ転送量の削減

課題分析

続いてパフォーマンス課題の分析です。フロント側では、React, Redux Toolkit, RTKQuery, Mantine UI などのライブラリを用いています。分析の結果、以下の2つが主要な課題として明らかになりました:

データの過剰な初期ロード
documentの初期ロードで、不必要に多くのデータを含んでいることが分かりました。特に、ユーザーが即座に必要としない情報までが、初期ロードの段階で読み込まれていました。
documentに含むデータというのは、グローバルオブジェクトを通してJavaScriptに吐き出すデータのことです。
ページのサーバー側では、MVCアーキテクチャによるフレームワークでhtmlのボイラープレート部分をSSRしています。生成されるdocumentのscriptに、グローバル(window)オブジェクトを定義してそこにサーバーサイドから送信するデータを格納することで、Reactがデータを読み込めるようにしています。
このようなデータ戦略は、サーバーフレームワークによるSSRとReactによるCSRを組み合わせる場合の方法の一つで、初期コンテンツ表示までの速度面で優れています。

非効率なデータフェッチ
データの取得には、windowオブジェクトの利用に加え、RTKQueryによるデータフェッチも採用しています。分析したところ、このデータフェッチや状態管理に関して、最適化不足であることが分かりました。ページ全体で一貫性のないデータフェッチ戦略により、役割が一部重複したデータを取得していたり、コンポーネント上でその取得データの整形や加工などを行っていたため、レンダリング時の計算量を増やしてしまっていました。

これらの課題を解決することを、改善の主な方針としました。

課題解決のアプローチ

window変数の削減と条件付きレンダリングの導入
課題分析で明らかになった、ページのロード時には不要なwindow変数の削減を行いました。この設計見直しに伴い、

  • 条件付きレンダリングの導入

  • 必要なデータを適宜フェッチ & キャッシュする方式への変更

が必要になったので、同様に実施しました。条件付きレンダリングはそれ自体がレンダリング時間の短縮を期待できる技法です。キャッシュ化は、厳密には必要になったからという訳ではなく、ページ滞在中のUX向上を目的に導入したのが背景であり、RTKQueryを用いたエンドポイント設定時に以下のように記述することで実現させています:

providesTags: () => [{ id: 'Pattern_List', type: 'Selection' }],

データフェッチの効率化とuseMemoの適用
分析結果に基づき、

  • 役割が一部重複したデータの取得やそのエンドポイント設定の除去

    • データ利用計画を再整理し、ページロード時に必要かそうでないかの基準でデータやエンドポイントを明確に分離または統合

  • コンポーネント上での取得データの整形や加工処理をuseMemo化

を行いました。
一方で、これらで対象となるデータは、ページロード完了後に条件付きでレンダリングされるようにしたコンポーネントの中で、必要に応じて(レンダリングされて初めて)フェッチされるものに限定されたため、ロード時間短縮に大きな効果が期待できるアプローチではありません。

改善結果

これらの改善により、負荷検証環境において、DOMContentLoaded (DCL)までの時間は改善前の7割ほどに短縮され、データ転送量は半減しました。最終的なFinishまでの時間としても、DCLの短縮分の削減を実現しました。
この結果は以下のように理解しています:
データ転送量削減には、window変数の削減自体が大きく貢献しています。そのデータ削減量は、documentサイズの減少量とほぼイコールであると考えられます。Reactによる仮想DOM構築時に必要だったそのデータ部分のJavaScript解析時間も、そのデータ出力の除去に応じて削減され、DCLは改善前の7割程度へと短縮されました。
一方で、実はそのデータが関連するページロード後の実際のDOMは、改善前の状態と条件付きレンダリングを導入した改善後の状態とでほぼ変わっておらず、Finishに至るまでのJavaScript実行量もさほど変わっていないと考えられるため、DCL減少分以上の短縮効果はなく、DCLの減少分がそのままFinishの削減分になったと推測しています。
ページロード後の実際のDOMが改善前と後とでほぼ変わらなかったのは、改善前の状態でUIライブラリ (Mantine UI)の最適化が効いてたからで、ロード時にペイントされないコンポーネント(モーダルなど)の中身はレンダリングされない挙動をしていたからです。

まとめ

このプロジェクトで、学生管理ページのデータ転送量を半減、ロード時間の3割程度削減を実現しました。今後も私たちは、サービスの品質向上とユーザーエクスペリエンスの改善に向けて、パフォーマンス改善などを通し技術的な挑戦を続けていきます。
ご覧いただきありがとうございました。