react实现一个多卡片的定时功能

151 阅读1分钟

代码展示

import React, {
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react';
import styles from './index.less';
import { Statistic } from 'antd';

import juxin from '../../../public/img/juxin.png';
import createNum from '../../../public/img/createNum.png';
import cathectic from '../../../public/img/cathectic.png';
import selectNum from '../../../public/img/selectNum.png';
import timekeeping from '/src/public/icon/timekeeping.png';
import { useDispatch } from 'umi';

const { Countdown } = Statistic;

interface cardData {
  title: string;
  openTime: any;
  curTime: any;
  tag: string;
  explain: string;
  id: number | string;
  cover: string;
  min: string | number;
  max: string | number;
  num: string | number;
  odds: string;
  periodsId: string;
  issueNo: string;
  type: number;
  PlayOdds: any;
}
interface cardItemType {
  cardList: cardData[];
  showCreateModal: (
    i: boolean,
    t: any,
    min: any,
    max: any,
    num: number | string,
    odds: string,
    id: number | string,
    curTime: string,
  ) => void;
  showCathecticModal: (
    i: boolean,
    config: {
      title: any;
      min: any;
      max: any;
      num: number | string;
      odds: string;
      id: number | string;
      periodsId: string;
    },
  ) => void;
  showPourModal: (
    i: boolean,
    config: {
      title: any;
      min: any;
      max: any;
      num: number | string;
      odds: string;
      id: number | string;
      issueNo: any;
      timeDiff: any;
      type: number;
      PlayOdds: any;
    },
  ) => void;
  cardConfig: {};
}
export default function CardItem({
  cardList,
  showCreateModal,
  showCathecticModal,
  showPourModal,
}: cardItemType) {
  const dispatch = useDispatch();
  const [isLoad, setIsLoad] = useState(false);
  const timeStampsRef = useRef<number[] | null>();

  // 在组件挂载时计算所有倒计时的时间戳
  useEffect(() => {
    const timestamps = cardList.map((item: any) => {
      const startTime = new Date(item.cur_time);
      const endTime = new Date(item.open_time);
      return endTime.getTime() - startTime.getTime() + Date.now();
    });
    timeStampsRef.current = timestamps;
  }, [cardList]);

  // 每秒轮询时间戳,检查是否有倒计时结束
  useEffect(() => {
    const timerId = setInterval(() => {
      const now = Date.now();
      const finished = timeStampsRef?.current.filter((ts) => ts <= now);
      if (finished.length > 0) {
        dispatch({
          type: 'gameModels/fetchPalyData',
          payload: {},
        });
        setIsLoad(!isLoad);
      }
    }, 1000);
    return () => {
      clearInterval(timerId);
    };
  }, [timeStampsRef, dispatch, isLoad]);

  const Cards = ({
    title,
    tag,
    explain,
    id,
    cover,
    min,
    max,
    num,
    odds,
    issueNo,
    type,
    PlayOdds,
    curTime,
    openTime,
    periodsId,
  }: cardData) => {
    let timeDiff = useMemo(() => {
      const timestamps = timeStampsRef.current;
      if (!timestamps) {
        const startTime = new Date(curTime);
        const endTime = new Date(openTime);
        return endTime.getTime() - startTime.getTime() + Date.now();
      }
      const index = cardList.findIndex((item: any) => item.id === id);
      if (index >= 0 && index < timestamps.length) {
        return timestamps[index];
      }
      return 0;
    }, [id, curTime, openTime, cardList]);

    return (
      <div className={styles.card} key={id}>
        <img className={styles.cover} src={cover} alt="" />
        <div className={styles.rightCtx}>
          <div className={styles.oneLine}>
            <div className={styles.title}>{title}</div>
            <div className={styles.countdown}>
              <img src={timekeeping} />
              <div className={styles.time}>
                <Countdown
                  valueStyle={{ color: '#fff' }}
                  value={timeDiff}
                  format="HH:mm:ss"
                  // onFinish={onFinish}
                />
              </div>
            </div>
          </div>
          <div className={styles.tag}>{tag}</div>
          <div className={styles.handle}>
            <img
              src={createNum}
              onClick={() =>
                showCreateModal(true, title, min, max, num, odds, id, issueNo)
              }
            ></img>
            <img
              src={cathectic}
              onClick={() =>
                showCathecticModal(true, {
                  title,
                  min,
                  max,
                  num,
                  odds,
                  id,
                  periodsId,
                })
              }
            ></img>
            {/*  */}
            <img
              src={selectNum}
              onClick={() =>
                showPourModal(true, {
                  title,
                  min,
                  max,
                  num,
                  odds,
                  id,
                  issueNo,
                  timeDiff,
                  type,
                  PlayOdds,
                })
              }
            ></img>
          </div>
          <div className={styles.explain}>{explain}</div>
        </div>
      </div>
    );
  };
  return (
    <div className={styles.main}>
      {cardList.map((item: any, index: number) => {
        return (
          <Cards
            title={item.name}
            curTime={item.cur_time}
            openTime={item.open_time}
            explain={item.remark}
            min={item.min}
            max={item.max}
            num={item.num}
            tag={`${item.min}-${item.max}`}
            cover={item.cover}
            odds={item.odds}
            id={item.id}
            key={index}
            issueNo={item.issue_no}
            periodsId={item.periods_id}
            type={item.type}
            PlayOdds={item.PlayOdds}
          />
        );
      })}
    </div>
  );
}

提几个重要的地方 定时器的数据数组要用useRef来保存 这样避免外部变化影响到组件内部更新导致定时器回退