UIでデバウンスとスロットルが重要な理由
スロットルされていないキー入力、スクロール、リサイズのハンドラーによるパフォーマンスコストと、それぞれの解決策を使う場面を理解します
「UIでデバウンスとスロットルが重要な理由」はCoddyKit上の無料React Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはReact Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 React Academyコースには全4レッスンが含まれています。
高頻度で発生するユーザーイベント
一部の DOM イベントは、非常に高い頻度で発生します。keypress イベントは、キー入力のたびに発生します。scroll イベントは、スクロール中に毎秒数十回発生します。resize イベントは、ユーザーがウィンドウの境界をドラッグしている間、連続的に発生します。すべてのイベントを個別に処理すると、ブラウザとサーバーの両方に過大な負荷がかかる可能性があります。
制限のないハンドラーのコスト
キー入力のたびに API 呼び出しを行う keypress ハンドラーがある場合、ユーザーが「React hooks」と入力すると(11 文字)、11 回のネットワークリクエストが発生し、その多くは不完全な検索語に対するものになります。同様に、スクロールのピクセル移動ごとにパララックスアニメーションを更新すると、毎秒数百回の React の再レンダリングが発生します。これは CPU、ネットワーク、バッテリーを浪費します。
デバウンスの動作
デバウンスは、イベントの発生が指定した期間停止するまで実行を遅延させます。ユーザーが入力を続けている間は、キー入力のたびにタイマーがリセットされます。そして、N ミリ秒間イベントが発生しなかった後に、ハンドラーが一度だけ実行されます。デバウンスは、「ユーザーが何かを終えた後にこれを実行する」という要件に適しています。
スロットルの動作
スロットルは、イベントが何回発生したかに関係なく、一定の時間間隔あたり最大 1 回に実行回数を制限します。ユーザーが高速にスクロールしても、100ms のスロットルを設定すれば、ハンドラーの実行回数は毎秒 10 回以下になります。スロットルは、「定期的に実行するが、N ms より短い間隔では実行しない」という要件に適しています。
デバウンスを使う場面
ユーザーが操作を止めた後の最終的な値だけが必要な場合は、デバウンスが適しています。代表的な例は、検索入力(入力が一段落してから API リクエストを送信する)、ウィンドウの resize ハンドラー(リサイズが終わってからレイアウトを再計算する)、サーバーに問い合わせるフォームフィールドのバリデーション(完全な入力を待ってから検証する)です。
スロットルを使う場面
連続的な操作中に定期的な更新を行いたい場合は、スロットルが適しています。代表的な例は、スクロール位置のハンドラー(最大 30fps で読了進捗バーやスティッキーヘッダーを更新する)、マウス移動の追跡(アナリティクス用にカーソル位置を記録する)、ドラッグイベントのハンドラー(過剰な処理を発生させず、ドラッグ可能な要素の位置を滑らかに更新する)です。
単純な実装には落とし穴があります
デバウンスやスロットルを十分に理解せずにゼロから実装すると、最終イベントを取りこぼす(トレーリングエッジ)、意図しないエッジで実行する、コンポーネントのアンマウント時にタイマーを後処理しないといったバグにつながります。通常は、すべてのエッジケースを正しく処理する lodash のようなライブラリの、十分に実績のある実装を使う方がよいでしょう。
lodash.debounce と lodash.throttle
Lodash には、リーディングエッジとトレーリングエッジの動作を指定できるオプション付きの _.debounce(fn, wait) と _.throttle(fn, wait) が用意されています。返される関数には、保留中の呼び出しを中止する .cancel() メソッドと、直ちに実行する .flush() メソッドがあります。React では、再レンダリングのたびに関数が作り直されないよう、これらを useRef でラップする必要があります。
パフォーマンス予算
スロットルされていないスクロールハンドラーによって、毎秒 50 回の React の再レンダリングが余分に発生するだけでも、特に性能の低いモバイルデバイスでは CPU を大きく消費する可能性があります。16ms のフレーム予算(60fps)では、フレーム落ちを避けるために、各再レンダリングを 16 ミリ秒未満で完了させる必要があります。デバウンスとスロットルは、フレームレートの問題に対する最初の防衛策です。
イベントハンドラーと状態更新の違い
高頻度で発生するすべてのハンドラーにデバウンスが必要なわけではありません。イベントハンドラーが状態を更新したり API を呼び出したりせず、単に値を読み取るだけの場合、たとえば最後のマウス位置を ref に記録するだけの場合は、デバウンスは不要です。状態更新、API 呼び出し、DOM の測定など、コストの高い処理を実行するハンドラーにだけデバウンスまたはスロットルを適用します。
デバウンス関数のキャンセル
コンポーネントがアンマウントされるときは、アンマウント後の状態更新を防ぐため、保留中のデバウンス呼び出しをキャンセルする必要があります。useRef を使ってデバウンス関数を保存している場合は、useEffect のクリーンアップで debouncedFn.cancel() を呼び出します。Lodash のデバウンス関数には、まさにこの目的のためにこのメソッドが用意されています。
デバウンスとスロットルの使い分け
ユーザーが検索フィールドへの入力を終えたときに API 呼び出しを発生させるには、どちらの手法を使うべきですか?
レッスンのまとめ:デバウンスとスロットル
keypress、scroll、resize などの高頻度イベントで、イベントが発生するたびにハンドラーを実行すると、パフォーマンスの問題が発生する可能性があります。デバウンスはイベントが発生しない状態を待つため、検索入力や resize ハンドラーに適しています。スロットルは頻度を制限するため、スクロールやドラッグに適しています。Lodash の実装を ref に保存して使い、コンポーネントのアンマウント時には必ずキャンセルします。
よくある質問
「UIでデバウンスとスロットルが重要な理由」レッスンは無料ですか?
はい。「UIでデバウンスとスロットルが重要な理由」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、React Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 React Academyコースには全4レッスンが含まれています。
「UIでデバウンスとスロットルが重要な理由」で何を学びますか?
スロットルされていないキー入力、スクロール、リサイズのハンドラーによるパフォーマンスコストと、それぞれの解決策を使う場面を理解します ブラウザで直接実行するハンズオンコードでReact Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
React Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのReact Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「UIでデバウンスとスロットルが重要な理由」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このReact Academyレッスンでコードを書いて実行できますか?
はい。すべてのReact Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- UIでデバウンスとスロットルが重要な理由
- useDebounceカスタムフックの実装
- useThrottleカスタムフックの実装
- 実践的な活用例:検索、スクロール、リサイズ