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

March 30, 2023 1405hotness 0likes 0comments

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:

  • the hook for countdown first needs a target time (targetDate), controls the number of
    seconds of time change (interval defaults to 1s), and then is the function (onEnd) triggered
    after the countdown is completed
  • The return parameter of

  • is more clear at a glance. It returns the value of two time differences (time). In more
    detail, it can be converted into the corresponding days, hours, minutes (formattedRes)

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:

  • A good hooks must have useMemo , useCallback and other api optimizations
  • when you encounter passing values in custom hooks, give priority to using useRef , and then consider using useState . You can directly use useLatest to prevent the value from being not the latest value
  • when encapsulating, you should put the stored value into useRef , set its initialization through a state, update the corresponding value in judging the circumstances, and make clear the specific meaning of participating parameters, such as useCreation and useEventListener

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.

InterServer Web Hosting and VPS

Aaron

Hello, my name is Aaron and I am a freelance front-end developer

Comments