欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

使用react render props实现倒计时的示例代码

程序员文章站 2022-03-13 18:53:16
react的组件模式可以观看michael chan的演讲视频,平时大家常听到的react模式也是hoc, hoc的使用场景很多,譬如react-redux的connect...

react的组件模式可以观看michael chan的演讲视频,平时大家常听到的react模式也是hoc, hoc的使用场景很多,譬如react-redux的connect,这里不赘述hoc相关,感兴趣可以自行了解。

首先是这样一个场景,我的业务需要实现倒计时,倒计时你懂得,倒计时经常应用在预告一个活动的开始,像秒杀,像开售抢购等,或者活动的截止。

使用react render props实现倒计时的示例代码

我们来梳理一下这个倒计时的功能:

  • 定时更新时间,以秒为度;
  • 可以更新倒计时的截止时间,比如从10月1日更新为10月2日;
  • 倒计时结束,执行对应结束逻辑;
  • 倒计时结束,开启另一个活动倒计时;
  • 同时有多个倒计时;

这个时候我便开始编码,考虑代码复用,我用class的模式实现一个倒计时:

class timer {
 constructor(time, countcb, timeoutcb) {
  this.countcb = countcb;
  this.timeoutcb = timeoutcb;
  this.setdelaytime(time);
 }

 intervalid = null;

 clearinterval = () => {
  if (this.intervalid) {
   clearinterval(this.intervalid);
  }
 }

 // 更新倒计时的截止时间
 setdelaytime = (time) => {
  this.clearinterval();

  if (time) {
   this.delaytime = time;
   this.intervalid = setinterval(() => {
    this.docount();
   }, 1000);
  }
 }

 docount = () => {
  const timediffsecond =
   `${this.delaytime - date.now()}`.replace(/\d{3}$/, '000') / 1000;

  if (timediffsecond <= 0) {
   this.clearinterval();
   if (typeof this.timeoutcb === 'function') {
    this.timeoutcb();
   }
   return;
  }

  const day = math.floor(timediffsecond / 86400);
  const hour = math.floor((timediffsecond % 86400) / 3600);
  const minute = math.floor((timediffsecond % 3600) / 60);
  const second = math.floor((timediffsecond % 3600) % 60);

  // 执行回调,由调用方决定显示格式
  if (typeof this.countcb === 'function') {
   this.countcb({
    day,
    hour,
    minute,
    second,
   });
  }
 }
}

export default timer;

通过class的方式可以实现我的上述功能,将格式显示交给调用方决定,timer只实现倒计时功能,这并没有什么问题,我们看调用方如何使用:

 // 这是一个react组件部分代码 
 componentdidmount() {
  // 开启倒计时
  this.countdownlivedelay();
 }

 componentdidupdate() {
  // 开启倒计时
  this.countdownlivedelay();
 }

 componentwillunmount() {
  if (this.timer) {
   this.timer.clearinterval();
  }
 }

 timer = null;

 countdownlivedelay = () => {
  const {
   countdowntime,
   ontimeout,
  } = this.props;

  if (this.timer) { return; }

  const time = countdowntime * 1000;

  if (time <= date.now()) {
   ontimeout();
  }
  // new 一个timer对象
  this.timer = new timer(time, ({ hour, minute, second }) => {
   this.setstate({
    timedelaytext: `${formatetimestr(hour)}:${formatetimestr(minute)}:${formatetimestr(second)}`,
   });
  }, () => {
   this.timer = null;

   if (typeof ontimeout === 'function') {
    ontimeout();
   }
  });
 }

 render() {
  return (
   <span style={styles.text}>{this.state.timedelaytext}</span>
  );
 }

查看这种方式的调用的缺点:调用方都需要手动开启倒计时,countdownlivedelay方法调用

总感觉不够优雅,直到我看到了react的render props, 突然灵关一现,来了下面这段代码:

let delaytime;
// 倒计时组件
class timecountdown extends component {
 state = {
  day: 0,
  hour: 0,
  minute: 0,
  second: 0,
 }

 componentdidmount() {
  delaytime = this.props.time;
  this.startcountdown();
 }

 componentdidupdate() {
  if (this.props.time !== delaytime) {
   delaytime = this.props.time;

   this.cleartimer();
   this.startcountdown();
  }
 }

 timer = null;

 cleartimer() {
  if (this.timer) {
   clearinterval(this.timer);
   this.timer = null;
  }
 }

 // 开启计时
 startcountdown() {
  if (delaytime && !this.timer) {
   this.timer = setinterval(() => {
    this.docount();
   }, 1000);
  }
 }

 docount() {
  const {
   ontimeout,
  } = this.props;

  // 使用math.floor((delaytime - date.now()) / 1000)的话会导致这里值为0,前面delaytime - date.now() > 0
  const timediffsecond = (delaytime - `${date.now()}`.replace(/\d{3}$/, '000')) / 1000;

  if (timediffsecond <= 0) {
   this.cleartimer();
   if (typeof ontimeout === 'function') {
    ontimeout();
   }
   return;
  }

  const day = math.floor(timediffsecond / 86400);
  const hour = math.floor((timediffsecond % 86400) / 3600);
  const minute = math.floor((timediffsecond % 3600) / 60);
  const second = math.floor((timediffsecond % 3600) % 60);

  this.setstate({
   day,
   hour,
   minute,
   second,
  });
 }

 render() {
  const {
   render,
  } = this.props;

  return render({
   ...this.state,
  });
 }
}

export default timecountdown;

具体timecountdown代码可戳这里

调用方:

import timecountdown from 'timecountdown';
function formatetimestr(num) {
 return num < 10 ? `0${num}` : num;
}
// 业务调用倒计时组件
class calltimer extends component {
 ontimeout = () => {
  this.forceupdate();
 }
 render() {
  // 传递render函数
  return (
   <span style={styles.statustext}>
    距直播还有
    <timecountdown
      time={time}
      ontimeout={() => { this.ontimeout(); }}
      render={({ hour, minute, second }) => {
       return (
        <span>
         {formatetimestr(hour)}:{formatetimestr(minute)}:{formatetimestr(second)}
        </span>
       );
      }}
     />
      </span>
  )
 }
}

对比这种方式,通过传递一个函数render方法给到timecountdown组件,timecountdown组件渲染时执行props的render方法,并传递timecountdown的state进行渲染,这就是render props的模式了,这种方式灵活、优雅很多,很多场景都可以使用这种方式,而无需使用hoc。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。