3

特定のイベント セットのイベント リスナーを設定するカスタム フックを React で作成しています。イベントの既定のセットが存在し、このカスタム フックのコンシューマーは、ほとんどのユース ケースでこれらをカスタマイズすることは想定されていません。通常、コンポーネントのマウント時にイベント リスナーを追加し、アンマウント時に削除する必要があります。ただし、フックの原則 (およびeslint(react-hooks/exhaustive-deps)lint ルール) に従って、監視するイベントのリストの変更を適切に処理したいと考えています。Reactフックでこれを達成するための最も慣用的な方法は何ですか?

すべてのイベント リスナーを削除し、イベントのリストが変更されたときに再度追加したいだけだと仮定すると、次のことを試みることができます。

const useEventWatcher = (
  interval = 5000,
  events = ['mousemove', 'keydown', 'wheel']
) => {
  const timerIdRef = useRef();

  useEffect(() => {
    const resetInterval = () => {
      if (timerIdRef.current) {
        clearInterval(timerIdRef.current);
      }

      timerIdRef.current = setInterval(() => { 
        console.log(`${interval} milliseconds passed with no ${events.join(', ')} events!`);
      }, interval)
    };

    events.forEach(event => window.addEventListener(event, resetInterval));

    // Don't want to miss the first time the interval passes without
    // the given events triggering (cannot run the effect after every render due to this!)
    resetInterval();

    return () => {
      events.forEach(event => window.removeEventListener(event, resetInterval));
    };
  }, [events, interval]);
}

残念ながら、これは意図したとおりに機能しません。パラメータのデフォルト値を指定したいことに注意してeventsください。現在のアプローチでそれを行うことはevents、カスタム フックが実行されるたびに異なる参照を指すことを意味します。これは、エフェクトも毎回実行されることを意味します (依存関係の比較が浅いため)。理想的には、参照ではなく、配列の内容に依存する効果を持つ方法が欲しいです。これを達成する最善の方法は何ですか?

4

2 に答える 2