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

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。

以上是 使用react render props实现倒计时的示例代码 的全部内容, 来源链接: utcz.com/z/312894.html

回到顶部