I Love ReactJS

Understand these 12 Hooks and make sure you can play React (5)

case 3: Hooks about time

here we mainly introduce three hooks about time: useTimeout ,
useInterval and useCountDown

useTimeout

useTimeout : execute once in a period of time

pass parameters as long as the function and delay time are needed. It is important to note that
when unloading, OK the timer after clearing it

detailed code:

    import { useEffect } from 'react';
    import useLatest from '../useLatest';


    const useTimeout = (fn:() => void, delay?: number): void => {

      const fnRef = useLatest(fn)

      useEffect(() => {
        if(!delay || delay < 0) return;

        const timer = setTimeout(() => {
          fnRef.current();
        }, delay)

        return () => {
          clearTimeout(timer)
        }
      }, [delay])

    };

    export default useTimeout;

useInterval

useInterval : execute

every time

is roughly the same as useTimeout , with an extra parameter of whether to render
for the first time immediate

detailed code:

    import { useEffect } from 'react';
    import useLatest from '../useLatest';


    const useInterval = (fn:() => void, delay?: number, immediate?:boolean): void => {

      const fnRef = useLatest(fn)

      useEffect(() => {
        if(!delay || delay < 0) return;
        if(immediate) fnRef.current();

        const timer = setInterval(() => {
          fnRef.current();
        }, delay)

        return () => {
          clearInterval(timer)
        }
      }, [delay])

    };

    export default useInterval;

useCountDown

useCountDown : hooks that simply control the countdown

as before, let's think about what this hook needs:

detailed code

    import { useState, useEffect, useMemo } from 'react';
    import useLatest from '../useLatest';
    import dayjs from 'dayjs';

    type DTime = Date | number | string | undefined;

    interface Options {
      targetDate?: DTime;
      interval?: number;
      onEnd?: () => void;
    }

    interface FormattedRes {
      days: number;
      hours: number;
      minutes: number;
      seconds: number;
      milliseconds: number;
    }

    const calcTime = (time: DTime) => {
      if(!time) return 0

      const res = dayjs(time).valueOf() - new Date().getTime(); //inserting value calculation

      if(res < 0) return 0

      return res
    }

    const parseMs = (milliseconds: number): FormattedRes => {
      return {
        days: Math.floor(milliseconds / 86400000),
        hours: Math.floor(milliseconds / 3600000) % 24,
        minutes: Math.floor(milliseconds / 60000) % 60,
        seconds: Math.floor(milliseconds / 1000) % 60,
        milliseconds: Math.floor(milliseconds) % 1000,
      };
    };

    const useCountDown = (options?: Options) => {

      const { targetDate, interval = 1000, onEnd } = options || {};

      const [time, setTime] = useState(() =>  calcTime(targetDate));
      const onEndRef = useLatest(onEnd);

      useEffect(() => {

        if(!targetDate) return setTime(0)

        setTime(calcTime(targetDate))

        const timer = setInterval(() => {
          const target = calcTime(targetDate);

          setTime(target);
          if (target === 0) {
            clearInterval(timer);
            onEndRef.current?.();
          }
        }, interval);
        return () => clearInterval(timer);
      },[targetDate, interval])

      const formattedRes = useMemo(() => {
        return parseMs(time);
      }, [time]);

      return [time, formattedRes] as const
    };

    export default useCountDown;

verify

    import React, { useState } from 'react';
    import { useCountDown } from '@/components'
    import { Button, Toast } from 'antd-mobile';

    const Index:React.FC<any> = (props)=> {

      const [_, formattedRes] = useCountDown({
        targetDate: '2022-12-31 24:00:00',
      });

      const { days, hours, minutes, seconds, milliseconds } = formattedRes;

      const [count, setCount] = useState<number>();

      const [countdown] = useCountDown({
        targetDate: count,
        onEnd: () => {
          Toast.show('finish')
        },
      });

      return (
        <div style={{padding: 20}}>
          <div> There are {days} days {hours} hours {minutes} minutes {seconds} seconds {milliseconds} milliseconds left from 24:00:00 on December 31, 2022</div>
          <div>
            <p style={{marginTop: 12}}>dynamic change:</p>
            <Button color='primary' disabled={countdown !== 0} onClick={() => setCount(Date.now() + 3000)}>
              {countdown === 0 ? 'begin' : `still ${Math.round(countdown / 1000)}s`}
            </Button>
            <Button style={{marginLeft: 8}} onClick={() => setCount(undefined)}>stop</Button>
          </div>
        </div>
      );
    }

    export default Index;

End

Summary

make a simple summary:

stocktaking

this article explains 12 custom hooks: usePow , useLatest , useCreation , useMount , useUnmount , useUpdate , useReactive , useEventListener , useHover , useTimeout , useInterval , useCountDown

the source of the material here is ahooks, but it is not exactly the same as that of ahooks.Interested partners can knock with their own hands and deepen their understanding by comparing the source code of ahooks .

I believe that with the help of this article, all of you should have a deeper understanding of Hooks like me. Of course, practice is the only criterion for testing truth, and knocking on code is the king.

Exit mobile version