index.js 2.46 KB
Newer Older
afc163's avatar
afc163 committed
1 2 3 4 5
import React, { Component } from 'react';

function fixedZero(val) {
  return val * 1 < 10 ? `0${val}` : val;
}
jim's avatar
jim committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
const initTime = props => {
  let lastTime = 0;
  let targetTime = 0;
  try {
    if (Object.prototype.toString.call(props.target) === '[object Date]') {
      targetTime = props.target.getTime();
    } else {
      targetTime = new Date(props.target).getTime();
    }
  } catch (e) {
    throw new Error('invalid target prop', e);
  }

  lastTime = targetTime - new Date().getTime();
  return {
    lastTime: lastTime < 0 ? 0 : lastTime,
  };
};
afc163's avatar
afc163 committed
24 25 26 27 28

class CountDown extends Component {
  constructor(props) {
    super(props);

jim's avatar
jim committed
29
    const { lastTime } = initTime(props);
afc163's avatar
afc163 committed
30 31 32 33 34 35

    this.state = {
      lastTime,
    };
  }

jim's avatar
jim committed
36 37 38 39 40 41 42 43 44 45
  static getDerivedStateFromProps(nextProps, preState) {
    const { lastTime } = initTime(nextProps);
    if (preState.lastTime !== lastTime) {
      return {
        lastTime,
      };
    }
    return null;
  }

afc163's avatar
afc163 committed
46 47 48 49
  componentDidMount() {
    this.tick();
  }

jim's avatar
jim committed
50 51
  componentDidUpdate(prevProps) {
    if (this.props.target !== prevProps.target) {
52
      clearTimeout(this.timer);
jim's avatar
jim committed
53
      this.tick();
afc163's avatar
afc163 committed
54 55 56 57 58 59 60 61 62 63 64 65
    }
  }

  componentWillUnmount() {
    clearTimeout(this.timer);
  }

  timer = 0;
  interval = 1000;
  // defaultFormat = time => (
  //  <span>{moment(time).format('hh:mm:ss')}</span>
  // );
jim's avatar
jim committed
66
  defaultFormat = time => {
afc163's avatar
afc163 committed
67 68 69
    const hours = 60 * 60 * 1000;
    const minutes = 60 * 1000;

70
    const h = Math.floor(time / hours);
jim's avatar
jim committed
71 72
    const m = Math.floor((time - h * hours) / minutes);
    const s = Math.floor((time - h * hours - m * minutes) / 1000);
afc163's avatar
afc163 committed
73
    return (
jim's avatar
jim committed
74 75 76
      <span>
        {fixedZero(h)}:{fixedZero(m)}:{fixedZero(s)}
      </span>
afc163's avatar
afc163 committed
77
    );
jim's avatar
jim committed
78
  };
afc163's avatar
afc163 committed
79 80 81 82 83 84 85
  tick = () => {
    const { onEnd } = this.props;
    let { lastTime } = this.state;

    this.timer = setTimeout(() => {
      if (lastTime < this.interval) {
        clearTimeout(this.timer);
jim's avatar
jim committed
86 87 88 89 90 91 92 93
        this.setState(
          {
            lastTime: 0,
          },
          () => {
            if (onEnd) {
              onEnd();
            }
94
          }
jim's avatar
jim committed
95
        );
afc163's avatar
afc163 committed
96 97
      } else {
        lastTime -= this.interval;
jim's avatar
jim committed
98 99 100 101 102 103 104 105
        this.setState(
          {
            lastTime,
          },
          () => {
            this.tick();
          }
        );
afc163's avatar
afc163 committed
106 107
      }
    }, this.interval);
jim's avatar
jim committed
108
  };
afc163's avatar
afc163 committed
109 110

  render() {
jim's avatar
jim committed
111
    const { format = this.defaultFormat, onEnd, ...rest } = this.props;
afc163's avatar
afc163 committed
112 113 114
    const { lastTime } = this.state;
    const result = format(lastTime);

jim's avatar
jim committed
115
    return <span {...rest}>{result}</span>;
afc163's avatar
afc163 committed
116 117 118 119
  }
}

export default CountDown;