首先对setInterval做了Hook化封装
import { useEffect, useRef } from 'react' /** * interTerval hooks组件 * @param fn 执行函数 * @param delay 时间 * @param options immediate为true时,先立即执行一次fn函数后再执行定时器 */ function useInterval( fn: () => void, delay: number | null | undefined, options?: { immediate?: boolean } ): void { const immediate = options?.immediate const timerRef = useRef<() => void>() timerRef.current = fn useEffect(() => { if (delay === undefined || delay === null) { return } if (immediate) { timerRef.current?.() } const timer = setInterval(() => { timerRef.current?.() }, delay) return () => { clearInterval(timer) } }, [delay]) } export default useInterval
实现倒计时Hook
import { useState, useEffect, useRef, useMemo } from 'react' import { useInterval } from './' interface ITime { /** 当前时间 */ currentTime?: number /** 结束时间 */ endTime?: number /** 另一种方式,不传当前时间和结束时间,直接传时间差 */ differTime?: number } interface ICbTime { d: number h: number m: number s: number } /** * 倒计时hooks * @param options 时间对象 * @param cb 倒计时完成时执行的回调函数 * @param noImmediate 时间传进来满足执行回调条件时,是否立即执行回调,默认false执行 */ function useCountDown( options: ITime, cb?: () => void, noImmediate?: boolean ): ICbTime { const { currentTime = 0, endTime = 0, differTime = 0 } = options const [diffTime, setDiffTime] = useState(0) /** 组件接收到参数时的时间 */ const entryTime = useRef<number>(0) /** 当前倒计时要求的时间差 */ const maxTime = useRef<number>(0) /** 是否可以执行回调 */ const isImplementCb = useRef(false) useEffect(() => { if (!isImplementCb.current) { isImplementCb.current = true } if ((currentTime > 0 && endTime > 0) || differTime > 0) { entryTime.current = new Date().getTime() maxTime.current = differTime > 0 ? differTime : endTime - currentTime if (maxTime.current <= 0 && noImmediate) { isImplementCb.current = false } setDiffTime(maxTime.current) } }, [currentTime, endTime, differTime]) useInterval( () => { const curtTimes = new Date().getTime() const TimeDifference = curtTimes - entryTime.current setDiffTime(maxTime.current - TimeDifference) }, diffTime <= 0 ? null : 1000 ) const timeObj = useMemo(() => { const time = diffTime > 0 ? diffTime / 1000 : 0 const d = Math.floor(time / (24 * 60 * 60)) const h = Math.floor((time / (60 * 60)) % 24) const m = Math.floor((time / 60) % 60) const s = Math.ceil(time % 60) if (diffTime <= 0 && isImplementCb.current) { /** * setTimeout用于解决react报错问题: * annot update during an existing state transition (such as within `render`). * Render methods should be a pure function of props and state. */ setTimeout(() => { cb?.() }, 0) } return { d, h, m, s } }, [diffTime]) return timeObj || ({} as ICbTime) } export default useCountDown
写个demo看一下效果
const TimeArea = () => { const { d, h, m, s } = useCountDown( { currentTime: 1631262176333, endTime: 1831062176333 }, () => { alert('倒计时结束') } ) return ( <div style={{ width: '200px', height: '200px' }}> 距离任务结束 {d}天<i>{h < 10 ? '0' + h : h}</i>: <i>{m < 10 ? '0' + m : m}</i>:<i>{s < 10 ? '0' + s : s}</i> </div> ) }
到此这篇关于React+Typescript实现倒计时Hook的方法的文章就介绍到这了,更多相关React+Typescript实现倒计时 内容请搜索NICE源码以前的文章或继续浏览下面的相关文章希望大家以后多多支持NICE源码!