index.js 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import React, { Component } from 'react';
  2. function fixedZero(val) {
  3. return val * 1 < 10 ? `0${val}` : val;
  4. }
  5. const initTime = props => {
  6. let lastTime = 0;
  7. let targetTime = 0;
  8. try {
  9. if (Object.prototype.toString.call(props.target) === '[object Date]') {
  10. targetTime = props.target.getTime();
  11. } else {
  12. targetTime = new Date(props.target).getTime();
  13. }
  14. } catch (e) {
  15. throw new Error('invalid target prop', e);
  16. }
  17. lastTime = targetTime - new Date().getTime();
  18. return {
  19. lastTime: lastTime < 0 ? 0 : lastTime,
  20. };
  21. };
  22. class CountDown extends Component {
  23. timer = 0;
  24. interval = 1000;
  25. constructor(props) {
  26. super(props);
  27. const { lastTime } = initTime(props);
  28. this.state = {
  29. lastTime,
  30. };
  31. }
  32. static getDerivedStateFromProps(nextProps, preState) {
  33. const { lastTime } = initTime(nextProps);
  34. if (preState.lastTime !== lastTime) {
  35. return {
  36. lastTime,
  37. };
  38. }
  39. return null;
  40. }
  41. componentDidMount() {
  42. this.tick();
  43. }
  44. componentDidUpdate(prevProps) {
  45. const { target } = this.props;
  46. if (target !== prevProps.target) {
  47. clearTimeout(this.timer);
  48. this.tick();
  49. }
  50. }
  51. componentWillUnmount() {
  52. clearTimeout(this.timer);
  53. }
  54. // defaultFormat = time => (
  55. // <span>{moment(time).format('hh:mm:ss')}</span>
  56. // );
  57. defaultFormat = time => {
  58. const hours = 60 * 60 * 1000;
  59. const minutes = 60 * 1000;
  60. const h = Math.floor(time / hours);
  61. const m = Math.floor((time - h * hours) / minutes);
  62. const s = Math.floor((time - h * hours - m * minutes) / 1000);
  63. return (
  64. <span>
  65. {fixedZero(h)}:{fixedZero(m)}:{fixedZero(s)}
  66. </span>
  67. );
  68. };
  69. tick = () => {
  70. const { onEnd } = this.props;
  71. let { lastTime } = this.state;
  72. this.timer = setTimeout(() => {
  73. if (lastTime < this.interval) {
  74. clearTimeout(this.timer);
  75. this.setState(
  76. {
  77. lastTime: 0,
  78. },
  79. () => {
  80. if (onEnd) {
  81. onEnd();
  82. }
  83. }
  84. );
  85. } else {
  86. lastTime -= this.interval;
  87. this.setState(
  88. {
  89. lastTime,
  90. },
  91. () => {
  92. this.tick();
  93. }
  94. );
  95. }
  96. }, this.interval);
  97. };
  98. render() {
  99. const { format = this.defaultFormat, onEnd, ...rest } = this.props;
  100. const { lastTime } = this.state;
  101. const result = format(lastTime);
  102. return <span {...rest}>{result}</span>;
  103. }
  104. }
  105. export default CountDown;