useThrottleカスタムフックの実装
スクロールなどの連続イベント中に値の更新頻度を制限するuseThrottleフックを構築します
「useThrottleカスタムフックの実装」はCoddyKit上の無料React Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはReact Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 React Academyコースには全4レッスンが含まれています。
スロットルはデバウンスより難しい
デバウンスは、イベントが発生するたびにタイマーをリセットするだけです。一方、スロットルでは、最後に実行した時刻を継続的に追跡し、次の実行に十分な時間が経過したかどうかを判断する必要があります。そのため、レンダーをまたいでタイムスタンプを保持する必要があり、実装はデバウンスより少し複雑になります。
lastRunTime への useRef の使用
最後に実行した時刻のタイムスタンプは、再レンダリングを発生させずにレンダーをまたいで保持する必要があるため、useRef が適しています。タイムスタンプを const lastRunTime = useRef(Date.now()) として保存します。state とは異なり、ref を更新しても再レンダリングは発生しないため、余分な処理サイクルを発生させずにスロットルのロジックを効率よく実行できます。
フックのシグネチャ
useThrottle(value, delay) フックは、入力値をスロットルしたものを返します。その契約は useDebounce と似ており、任意の値とミリ秒単位の遅延時間を受け取り、スロットルされた値を返します。コンポーネントでは同じ方法で使用できるため、異なるタイミング制御が必要な場合にそのまま置き換えられます。
トレーリングエッジの実装
トレーリングエッジのスロットルは、各インターバルの終わりに値を更新します。新しい値が届いたら、残りのインターバル時間分の setTimeout をスケジュールします: delay - (Date.now() - lastRunTime.current)。タイマーが発火したら状態を更新し、新しい lastRunTime を記録します。クリーンアップで以前のタイマーをキャンセルしてください。
リーディングエッジの実装
リーディングエッジのスロットルは、最初の値をすぐに適用し、インターバルが終了するまで後続の値を無視します。Date.now() - lastRunTime.current >= delay を確認し、条件を満たしていれば状態を更新して時刻を記録します。満たしていなければ更新をスキップします。これにより、最初の操作にはすぐ反応し、その後はクールダウン期間を設けられます。
リーディングとトレーリングの組み合わせ
最適な UX では、多くの場合この2つを組み合わせます。最初のイベントにはすぐに反応し(リーディング)、その後、インターバルの経過後に最終状態も確実に適用します(トレーリング)。これにより、ユーザーは最初の操作に対する素早い反応を確認でき、動きが止まった後には最終的な値が必ず適用されるため、終了時に古い状態が残るのを防げます。
タイムアウトIDへのuseRefの使用
保留中のタイムアウトIDを useRef に保存します: const timeoutRef = useRef(null)。新しいタイムアウトをスケジュールする前に clearTimeout(timeoutRef.current) を呼び出し、既存のタイムアウトがあればキャンセルします。これにより、複数のタイマーが重なって1つのスロットル間隔内に複数回更新されるのを防げます。
アンマウント時のクリーンアップ
useEffect のクリーンアップでは clearTimeout(timeoutRef.current) を呼び出し、コンポーネントのアンマウント時に保留中のトレーリング更新をキャンセルしてください。これを行わないと、アンマウント後に保留中のタイムアウトが発火し、アンマウント済みのコンポーネントの状態を更新しようとして、Reactの警告が発生する可能性があります。
スロットルされたコールバックという選択肢
値を基にするフックの代わりに、useCallback を基にしたスロットルフックを作成できます。useThrottledCallback(fn, delay) は、スロットルされた関数を返します。分析トラッカーのように、スロットルしたい対象がリアクティブな値ではなく関数呼び出しの場合に、こちらのほうが柔軟です。
フェイクタイマーを使ったスロットルのテスト
Jestのテストでは、jest.useFakeTimers() を使って時間を制御します。1000msの遅延でスロットルを設定し、値を10回すばやく変更した後、フェイクタイマーを500ms進めて更新が1回または2回だけ発生したことを確認します。さらに500ms進め、トレーリング更新が発火することを検証します。これにより、スロットルの動作を決定論的に検証できます。
Reactのモデルにおけるスロットル
Reactは、レンダー中の状態更新をバッチ処理します。状態更新に対して動作するスロットルは、このモデル内で問題なく機能します。ただし、React 18のConcurrent Modeでは、レンダーが中断される可能性があります。Date.now() による実際の経過時間に基づくスロットルロジック自体は、Reactのスケジューリングの影響を受けません。
スロットルのトレーリングエッジとリーディングエッジ
「トレーリング」スロットルは、どちらのエッジで発火しますか?
レッスンのまとめ: useThrottleフック
スロットルでは、useRef を使って最後に実行した時刻を追跡する必要があります。フックでは、リーディングエッジ(即時)、トレーリングエッジ(遅延)、またはその両方を実装できます。タイムアウトIDは必ずrefに保存し、クリーンアップでキャンセルしてください。関数を対象にする場合は、useThrottledCallback パターンを使用するのが適しています。信頼性を高めるため、フェイクタイマーでテストしてください。
よくある質問
「useThrottleカスタムフックの実装」レッスンは無料ですか?
はい。「useThrottleカスタムフックの実装」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、React Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 React Academyコースには全4レッスンが含まれています。
「useThrottleカスタムフックの実装」で何を学びますか?
スクロールなどの連続イベント中に値の更新頻度を制限するuseThrottleフックを構築します ブラウザで直接実行するハンズオンコードでReact Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
React Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのReact Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「useThrottleカスタムフックの実装」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このReact Academyレッスンでコードを書いて実行できますか?
はい。すべてのReact Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- UIでデバウンスとスロットルが重要な理由
- useDebounceカスタムフックの実装
- useThrottleカスタムフックの実装
- 実践的な活用例:検索、スクロール、リサイズ