[react]react HooksでのInterval()の使用問題の設定


自動スライド機能を実現するには、setInterval()を使用する必要があるが、要求に従って操作しなかった.そこで、私は問題の状況、原因、解決方法を学び始め、学習の内容に基づいて総括しようとしました.
まず、postingに関連する問題を解決したuseInterval custom hookの開発者はDan Abramovであり、まずテキストを翻訳したJAkeseo me setIntervalコンポーネントの使用時の問題 postingを発見し、読み、理解に大いに役立つ.
目次
  • 問題状況と原因分析
  • Solution - useInterval Hooks
  • useInterval Hooks説明
  • 1.問題状況及び原因分析
    Case 1
    function Test(){
      setInterval(()=>{
        setCurrentIndex(currentIndex => currentIndex + 1);
      },1000)
    }
    JavaScriptでは上記の内容が使用されている可能性がありますが、reactではステータスが変化するとアプリケーションが再表示されるため、setInterval()関数は無限に実行されます.
    Case 2
    case 1を体験したことがある場合、useEffect() hookは、1回目のレンダリング時にのみ以下のように実行されると考えられます.
    useEffect(()=>{
      setInterval(()=>{
        setCurrentIndex(currentIndex => currentIndex + 1);
      },1000)
      return () => clearInterval(id);
    },[])
    ただし、空の配列をuseEffect() Hookの2番目のパラメータとして渡すと、1回目のみ実行されるため、useEffect()内部では更新後のcurrentIndex値が分からないため、コンソールは初期値0のみを撮影する.
    Case 3
    case 2の問題により状態が変化した場合に実行するために、以下の内容を記述することもできる.
    useEffect(()=>{
      setInterval(()=>{
        console.log(currentIndex);
        setCurrentIndex(currentIndex => currentIndex + 1);
      },1000)
      return () => clearInterval(id);
    },[currentIndex])
    しかし、2番目のパラメータとして伝達される依存配列内の値がuseEffect()関数で修正されるため、無限ループに陥る.
    🤔 では、どうすればこの問題を解決できるのでしょうか.useEffect()を直接使用してcustom interval hookを作成すれば解決できます.
    2. Solution - useInterval Hooks
    🔑 ソリューションの核心はsavedCallback変数を導入することであり、時間間隔を変更せずに変更し、最近の時間間隔をコールバックすることができます.
    まず、ソリューションコードは次のとおりです.
    function useInterval(callback, delay) {
        const savedCallback = useRef();
        useEffect(() => {
            savedCallback.current = callback;
        }, [callback]);
    
        useEffect(() => {
            function tick() {
                savedCallback.current();
            }
            if (delay !== null) {
                let id = setInterval(tick, delay);
                return () => clearInterval(id);
            }
        }, [delay]);
    }
    
    function Test(){
      const [count, setCount] = useState(0);
    
      useInterval(()=>{
        setCount(count => count+1);
      }, 1000);
    }
    上記のコードから,useRefの代わりにsetIntervalを用いてuseIntervalというcustom interval hooksを作成した.
    3.UseInterval Hooksの説明useInterval関数をマイニングします.
    function useInterval(callback, delay) {
        const savedCallback = useRef();
        useEffect(() => {
            savedCallback.current = callback;
        }, [callback]);
    
        useEffect(() => {
            function tick() {
                savedCallback.current();
            }
            if (delay !== null) {
                let id = setInterval(tick, delay);
                return () => clearInterval(id);
            }
        }, [delay]);
    }
    1)UseRef利用useInterval hookを表示すると、コールバック関数とdelayが受信され、userEffectの内部にコールバック関数Callbackが保存されます.現存する
    const savedCallback = useRef();
    この場合、useIntervalがuseRefフックを使用するのは、レンダリングを防止するためです.useRefは、関数プログラミングによって使用されるrefによって初期化されたrefオブジェクト{current: null}を返し、返されたオブジェクトは、エレメントのライフサイクル全体にわたって変わらず、useRefによって管理された値は変更されても再レンダリングされません.
    🤔 useStateを使うとどうなりますか?
    const [count, setCount] = useState(0);
    
    useInterval(()=>{
      setCount(count => count+1);
    }, 1000);
    useStateを使用してデータを管理する場合、値が変更されると再レンダリングが発生するため、useEffect()の内部ではsavedCallbackの値が変更されるたびに再レンダリングが発生するため、2番目のuseEffect()の内部でsavedCallbackの値をチェックすると、初期値のみが取得されます.
    2)コールバック関数を格納するUserEffectフック
    useEffect(() => {
      savedCallback.current = callback;
    }, [callback]);
    上記のコードによれば、callbackデータを変更するたびにuseEffect()が実行され、savedCallbackの現在値が新しいcallbackデータに更新される.
    🤔 なぜuseInterval()に関数を渡し、内部で値を更新するのですか?
    前に紹介した問題の状況を考えれば、この点は理解できます.
    1.useEffect()依存配列を渡さない場合は、レンダリングのたびに実行されます.
    2.useEffect()の2番目のパラメータに空の配列を渡すと、1回目のレンダリング時にのみ実行され、hook内部では変化するデータ値は得られません.
    3.useEffect()は、特定のデータ変更時に実行できますが、useEffect()の内部で更新値に依存するデータは、無限ループに陥ります.
    この問題を解決するために、useInterval()フックはレンダリングのたびに実行され、更新されたcount値を有し、更新されたcount値の関数をuseIntervalフックに渡し、内部からCallbackを保存する.currentに保存し、useEffect hook内部でも新しいcount値を取得できます.
    3)setIntervalを呼び出すUserEffectフック
    1番目のuseEffect Hookによってコールバック関数が保存される場合、2番目のuseEffectは、そのコールバック関数をsetInterval関数に渡して実行する必要がある.
    useEffect(() => {
            function tick() {
                savedCallback.current();
            }
            if (delay !== null) {
                let id = setInterval(tick, delay);
                return () => clearInterval(id);
            }
        }, [delay]);
    上記のuseEffectはdelay変更時に実行され、delayが空の値でない場合、setInterval関数を呼び出してコールバック関数を実行します.
    このように記入するとuseEffect()が無限に動作しないようにし、変更が遅延した場合にのみタイマ2を再実行します.1番目のuseEffect()は、コールバック関数が変化するたびに更新されるので、最終的に2番目のuseEffect()内のsetInterval()関数は、再実行する必要がなく、新しい更新されたコールバック関数を実行することができる.
    このときnull check delayは、Intervalを一時停止できるようにするため、null indelayがuseIntervalに伝達されると、setInterval関数は実行されなくなる.return () => clearInterval(id);部分はclean-up関数であり、クラスコンポーネントはcomponentWillUnmountというライフサイクル法を用いて実現され、関数コンポーネントはuseEffect()に伝達された関数のreturn関数を用いて実現される.useEffect()内で1つの関数が返される場合、この関数は、不要な動作を除去したり、メモリの漏洩を防止したりするために、構成部品のアンロード時に実行することができる.
    `