react的组件模式可以观看MichaelChan的演讲视频,平时大家常听到的react模式也是HOC,HOC的使用
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倒计时