INPの改善:Reactアプリの「もっさり感」を解消する方法
ダッシュボードの動作が重く感じられる。APIは高速。Lighthouseのスコアは良好。それなのに、クリックするたびにラグが発生する。
それはINPの問題です。
Interaction to Next Paint (INP) は、ページがユーザーの操作に反応するまでにかかる時間を測定します。2024年3月に First Input Delay (FID) に代わって導入されました。FIDは最初のクリックのみを対象としていましたが、INPはすべてのインタラクションを監視します。
INPスコアが200ms未満であれば高速に感じられ、500msを超えると動作が重く感じられます。
INPを改善するには、以下の3つのフェーズに分けて考えます。
- Input Delay(入力遅延) – クリックしてからコードが実行されるまでの時間。メインスレッドがビジー状態のときに発生します。
- Processing Time(処理時間) – 関数やReactのステート更新が実行されている時間。
- Presentation Delay(描画遅延) – コードの実行が完了してから、ブラウザが画面をペイント(描画)するまでの時間。
Input Delayの改善
長いタスクはメインスレッドをブロックします。タスクの実行時間が50msを超えると、クリック操作が停滞します。scheduler.yield() を呼び出して長いタスクを小さなチャンクに分割することで、ブラウザがタスクの合間にクリックを処理できるようにします。
Processing Timeの改善
ReactのTransition APIを使用して、UIの応答性を維持します。
startTransition– 緊急性の低い更新をラップします。Reactは重い更新を一時停止して、新しいクリックを処理できます。useDeferredValue– 即座に更新する必要のない値を遅延させます。
これらのAPIはコード自体の速度を上げるものではありません。コードを「中断可能(interruptible)」にすることで、INPを低下させます。
Presentation Delayの改善
DOM要素が多すぎると、ペイントが遅くなります。
- CSSで
content-visibility: autoを適用し、画面外の要素のレンダリングをスキップします。 - レイアウト・スラッシング(Layout Thrashing)を防ぎます。同じループ内でスタイルの読み取りと書き込みを繰り返さないでください。代わりに、読み取りと書き込みをまとめて(バッチ処理して)行います。
- 長いリストは仮想化(Virtualize)します。
測定方法
Lighthouseはラボ環境で実行されるため、実際のユーザーのようにボタンをクリックすることはできません。web-vitals ライブラリをインストールして、実際のユーザーからのデータを取得しましょう。
