index.js 2.47 KB
Newer Older
afc163's avatar
afc163 committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
import React, { Component } from 'react';

function fixedZero(val) {
  return val * 1 < 10 ? `0${val}` : val;
}

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

    const { lastTime } = this.initTime(props);

    this.state = {
      lastTime,
    };
  }

  componentDidMount() {
    this.tick();
  }

  componentWillReceiveProps(nextProps) {
    if (this.props.target !== nextProps.target) {
24
      clearTimeout(this.timer);
afc163's avatar
afc163 committed
25
      const { lastTime } = this.initTime(nextProps);
jim's avatar
jim committed
26 27 28 29 30 31 32 33
      this.setState(
        {
          lastTime,
        },
        () => {
          this.tick();
        }
      );
afc163's avatar
afc163 committed
34 35 36 37 38 39 40 41
    }
  }

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

  timer = 0;
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
42

afc163's avatar
afc163 committed
43
  interval = 1000;
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
44

jim's avatar
jim committed
45
  initTime = props => {
afc163's avatar
afc163 committed
46 47 48 49 50 51 52 53 54 55 56 57 58 59
    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 {
60
      lastTime: lastTime < 0 ? 0 : lastTime,
afc163's avatar
afc163 committed
61
    };
jim's avatar
jim committed
62
  };
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
63

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

71
    const h = Math.floor(time / hours);
jim's avatar
jim committed
72 73
    const m = Math.floor((time - h * hours) / minutes);
    const s = Math.floor((time - h * hours - m * minutes) / 1000);
afc163's avatar
afc163 committed
74
    return (
jim's avatar
jim committed
75
      <span>
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
76 77 78 79 80
        {fixedZero(h)}
        :
        {fixedZero(m)}
        :
        {fixedZero(s)}
jim's avatar
jim committed
81
      </span>
afc163's avatar
afc163 committed
82
    );
jim's avatar
jim committed
83
  };
ι™ˆεΈ…'s avatar
ι™ˆεΈ… committed
84

afc163's avatar
afc163 committed
85 86 87 88 89 90 91
  tick = () => {
    const { onEnd } = this.props;
    let { lastTime } = this.state;

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

  render() {
jim's avatar
jim committed
117
    const { format = this.defaultFormat, onEnd, ...rest } = this.props;
afc163's avatar
afc163 committed
118 119 120
    const { lastTime } = this.state;
    const result = format(lastTime);

jim's avatar
jim committed
121
    return <span {...rest}>{result}</span>;
afc163's avatar
afc163 committed
122 123 124 125
  }
}

export default CountDown;