首页 > 其他分享 >使用hooks实现一个倒计时组件

使用hooks实现一个倒计时组件

时间:2022-12-20 16:36:05浏览次数:47  
标签:current const hooks 60 倒计时 moment deadline 组件 millisec

 

 要求可以每秒自动更新并返回当前剩余时间,其返回值满足以下定义:

// 返回值定义
interface Countdown {
expired: boolean; // 是否已到期
days: number; // 剩余天数(整数),最小为0
hours: number; // 剩余小时数(整数),最大为 23,最小为0
minutes: number; // 剩余分钟数(整数),最大为 59,最小为0
seconds: number; // 剩余秒数(整数),最大为 59,最小为0
}
Notice:
若剩余时间为0,则停止计时
应用程序在压后台时为优化性能,页面容器的tick会变慢(setInterval 1s,可能实际2s以上才会触发一次),基于该情况,请考虑如何准确计时

import { useEffect, useState } from 'react';
import moment from 'moment';

// 入参
export interface ICountdown {
  deadline: string;
  format?: 'YYYY-MM-DD HH:mm:ss' | string;
}
// 返回值
export type Remains = Record<'day' | 'hour' | 'minute' | 'second', number>;

const useCountdown = ({
  deadline,
  format = 'YYYY-MM-DD HH:mm:ss',
}: ICountdown): Remains => {
  // 由于 moment() 返回对象,setCurrent 修改值后指针不变,无法在 useEffect 中捕获变化,所以这里定义了一个 updater 用于 useEffect 捕获时间更新
  const [{ current, updater }, setCurrent] = useState({
    current: moment(),
    updater: 0,
  });
  const [remains, setRemains] = useState<Remains>({
    day: 0,
    hour: 0,
    minute: 0,
    second: 0,
  });
  useEffect(() => {
    const timer = window.setInterval(() => {
      current.isSameOrAfter(moment(deadline, format))
        ? clearInterval(timer)
        : setCurrent(prev => ({
            current: prev.current.add(1, 's'),
            updater: prev.updater + 1,
          }));
    }, 1000);
    return () => clearInterval(timer);
  }, [deadline]);

  // current 变化,计算相差多长时间
  useEffect(() => {
    let millisec = moment(deadline, format).valueOf() - current.valueOf();
    // 处理 millisec 可能为负数的情况
    millisec = millisec >= 0 ? millisec : 0;
    // 用毫秒数得到秒、分、小时和天
    setRemains({
      day: Math.floor(millisec / (1000 * 60 * 60 * 24)),
      hour: Math.floor((millisec / (1000 * 60 * 60)) % 24),
      minute: Math.floor((millisec / (1000 * 60)) % 60),
      second: Math.round((millisec / 1000) % 60),
    });
  }, [updater]);

  return remains;
};

export default useCountdown;

  

 

 

 

// countdown
import React, { useMemo } from 'react';
import useCountdown from '@/components/Countdown';
import moment from 'moment';

const Index = () => {
  const deadline = useMemo(
    () =>
      moment()
        .add(4, 's')
        .add(1, 'm')
        .add(1, 'h')
        .add(1, 'd')
        .format('YYYY-MM-DD HH:mm:ss'),
    [],
  );
  const { day, hour, minute, second } = useCountdown({
    // deadline: '2021-04-22 17:49:00',
    deadline,
  });

  return <h1>{`${day}天${hour}时${minute}分${second}秒`}</h1>;
};

export default Index;

  

标签:current,const,hooks,60,倒计时,moment,deadline,组件,millisec
From: https://www.cnblogs.com/judyhuayu/p/16994533.html

相关文章