首页 > 编程 > JavaScript > 正文

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

2019-11-19 12:23:21
字体:
来源:转载
供稿:网友

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

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

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

  • 定时更新时间,以秒为度;
  • 可以更新倒计时的截止时间,比如从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。

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

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表