今天我们来看下react中如何实现定时器调用的功能!
下面实现的是日期实时更新的效果,看起来比较简单,我们现在用不同的方式来实现这种效果
react&&class&&js组件
import React, { Component } from "react";
export default class Clock extends Component {
constructor(props) {
super(props);
this.state = {
time: new Date(+new Date() + 8 * 3600 * 1000)
.toISOString()
.replace(/T/g, " ")
.replace(/\.[\d]{3}Z/, "")
};
}
componentWillMount() {
this.timer = setInterval(() => {
this.setState({
time: new Date(+new Date() + 8 * 3600 * 1000)
.toISOString()
.replace(/T/g, " ")
.replace(/\.[\d]{3}Z/, "")
});
});
}
componentWillUnmount() {
//卸载的时候清除掉定时器,释放内存
clearInterval(this.timer);
}
render() {
const { time } = this.state;
return (
<div>
<h2>{time}</h2>
</div>
);
}
}
react&&class&&ts
起初觉得实现起来跟在js中差不多,但是实现过程遇到了一些坑点,比较让人摸不着头脑,特此记录下!
1.关于propType,StateType的类型约束
不加类型约束,直接爆红,所以此处必须加上我们预传递的props,state
2. constructor(props:any)
props后面的类型约束也不能省略,即使不知道我们就设为any即可解决红波浪线
3.下面是实现的反例,会报错
import React, { Component } from 'react'
type StateType = {
time: string,
};
type propType = {
};
export default class Timer extends Component<propType,StateType> {
constructor(props:any) {
super(props)
this.state = {
time: new Date(+new Date() + 8 * 3600 * 1000).toISOString().replace(/T/g, ' ').replace(/\.[\d]{3}Z/, ''),
}
}
componentWillMount() {
this.inter = window.setInterval(() => {
this.setState({
time: new Date(+new Date() + 8 * 3600 * 1000).toISOString().replace(/T/g, ' ').replace(/\.[\d]{3}Z/, '')
})
},1000)
}
componentWillUnmount() {
clearTimeout(this.inter)
}
render() {
console.log(this.state.time)
const { time } = this.state
return <div>3333
<h2>{ time }</h2>
</div>
}
}
像在js的class中那样,我们定义interval的返回值,代码会爆红,
js中的思维,我们一般会设置一个null来定义定时器的返回
但是ts中不行的,这里的坑困扰了很久,查资料研究发现
我们在js中
直接写setInterval()是用node的定时器,那么我们只需要 window.setInterval() 这样子调用就能用浏览器自带定时器
于是尝试着下面这样写,在运行就可以正常显示实时的时间
还是按照js的思维,也是行不通
最后按照react的修改值只能用setState方法的思维,最终实现了效果
完整的代码
import React, { Component } from 'react'
type StateType = {
time: string,
inter: number
};
type propType = {
};
export default class Timer extends Component<propType,StateType> {
constructor(props:any) {
super(props)
this.state = {
time: new Date(+new Date() + 8 * 3600 * 1000).toISOString().replace(/T/g, ' ').replace(/\.[\d]{3}Z/, ''),
inter:0
}
}
componentWillMount() {
/* this.inter = window.setInterval(() => {
this.setState({
time: new Date(+new Date() + 8 * 3600 * 1000).toISOString().replace(/T/g, ' ').replace(/\.[\d]{3}Z/, '')
})
},1000) */
this.setState({
//主要此处的赋值必须是这样,暂时不知道还有没有别的实现方式
//两层嵌套的setState,看着有点怪异
inter: window.setInterval(() => {
this.setState({
time: new Date(+new Date() + 8 * 3600 * 1000).toISOString().replace(/T/g, ' ').replace(/\.[\d]{3}Z/, '')
})
})
})
}
componentWillUnmount() {
clearTimeout(this.state.inter)
}
render() {
console.log(this.state.time)
const { time } = this.state
return <div>
<h2>{ time }</h2>
</div>
}
}
react&&hooks&&js
实现的比较顺利
import React, { useState, useEffect } from "react";
function Clock() {
const [time, setTime] = useState(
new Date(+new Date() + 8 * 3600 * 1000)
.toISOString()
.replace(/T/g, " ")
.replace(/\.[\d]{3}Z/, "")
);
//处理副作用部分
useEffect(() => {
//定义定时器的引用
const timer = setInterval(() => {
setTime(
new Date(+new Date() + 8 * 3600 * 1000)
.toISOString()
.replace(/T/g, " ")
.replace(/\.[\d]{3}Z/, "")
);
}, 1000);
return () => {
//组件销毁时清除定时器引用
clearInterval(timer);
};
// [] 为空说明需要一直执行,没有依赖,有值的情况下是依赖值变化了才会执行到effect副作用
}, []);
return <div>{time}</div>;
}
export default Clock;
react&&hook&&ts
import React, { useState, useEffect } from "react";
function Clock() {
const [time, setTime] = useState(
new Date(+new Date() + 8 * 3600 * 1000)
.toISOString()
.replace(/T/g, " ")
.replace(/\.[\d]{3}Z/, "")
);
//处理副作用部分
useEffect(() => {
//定义定时器的引用,需要区分是nodejs的定时器还是浏览器的定时器
const timer:number = window.setInterval(() => {
setTime(
new Date(+new Date() + 8 * 3600 * 1000)
.toISOString()
.replace(/T/g, " ")
.replace(/\.[\d]{3}Z/, "")
);
}, 1000);
return () => {
//组件销毁时清除定时器引用
clearInterval(timer);
};
// [] 为空说明需要一直执行,没有依赖,有值的情况下是依赖值变化了才会执行到effect副作用
}, []);
return <div>{time}</div>;
}
export default Clock;
一个小小的定时器功能,在ts中会遇到这样的坑点,惯性思维真的会害人!打完收工~~