react 函数组件实现:实施倒计时

272 阅读1分钟

背景:

实际工作中遇到这么一个需求,后端只给了截止时间,要来个实时倒计时的展示;刚拿到这个需求时,惯性思维,写一个函数 就好了;结果试了半天不行,最后查阅,获得启发,还是需要封装一个组件的;

import * as React from 'react';
import styles from './index.less';
const { useState, useEffect, useRef } = React;

interface IProps {
  timeStamp: any;
}

/**
 * 组件:倒计时组件
 * @param props:传入的时间戳是,以秒单位的,不是毫秒
 * @returns
 */
const CountDown = (props: IProps) => {
  const { timeStamp } = props;
  const intervalRef = useRef<any>(null);

  const now: any = Math.round(new Date().getTime() / 1000).toString(); // 获取当前时间
  const end: any = timeStamp; // 设置截止时间

  const [leftTime, setLeftTime] = useState(end - now); // 时间间隔
  const [day, setDay] = useState<any>(''); // 天
  const [h, setHours] = useState<any>(''); // 小时
  const [m, setMinutes] = useState<any>(''); // 分钟
  const [s, setSeconds] = useState<any>(''); // 秒

  useEffect(() => {
    if (leftTime > 0) {
      intervalRef.current = setInterval(() => {
        const newNow: any = Math.round(new Date().getTime() / 1000).toString(); // 重新获取当前时间

        const newLeftTime = timeStamp - newNow;

        setLeftTime(() => newLeftTime); // 计算新的时间间隔数值
        const tempDay = Math.floor((newLeftTime / 60 / 60 / 24) % 24);
        const hours = Math.floor((newLeftTime / 60 / 60) % 24) < 10 ? `0${Math.floor((newLeftTime / 60 / 60) % 24)}` : Math.floor((newLeftTime / 60 / 60) % 24);
        const minutes = Math.floor((newLeftTime / 60) % 60) < 10 ? `0${Math.floor((newLeftTime / 60) % 60)}` : Math.floor((newLeftTime / 60) % 60);
        const seconds = Math.floor(newLeftTime % 60) < 10 ? `0${Math.floor(newLeftTime % 60)}` : Math.floor(newLeftTime % 60);
        setDay(() => tempDay);
        setHours(() => hours); // 函数写法 设置小时
        setMinutes(() => minutes); // 函数写法 设置分钟
        setSeconds(() => seconds); // 函数写法保证值在setInterval里更新,避免useEffect的bug
      }, 1000);
    } else {
      setLeftTime(0);
      setDay(0);
      setHours(0);
      setMinutes(0);
      setSeconds(0);
      clearInterval(intervalRef.current);
    }
    return () => clearInterval(intervalRef.current);
  }, []); // 不传依赖

  return (
    <>
      {leftTime <= 0 && (
        <span className={styles.timeWrap}>
          <span>{0}</span><span>{0}</span>小时
          <span>{0}</span></span>
      )}
      {leftTime > 0 && (
        <span className={styles.timeWrap}>
          <span>{day}</span><span>{h}</span>小时
          <span>{m}</span></span>
      )}
    </>
  );
};

export default CountDown;