React+Typescript實現倒計時Hook的方法
首先對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實現倒計時 內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 詳解如何構建自己的react hooks
- React報錯解決之ref返回undefined或null
- ahooks控制時機的hook實現方法
- React Native 中實現倒計時功能
- React報錯之Object is possibly null的問題及解決方法