React Native实现验证码倒计时功能
实现倒计时功能使用的是核心方法 setInterval,setInterval() 方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭。
startCountDown() {
this.interval = setInterval(() => {
this.setState({
countdown: this.getCountdown() - 1
});
},1000);
}
当 App 切换至后台之后,setInterval 将不会执行,而当 App 从后台切换至前台时,setInterval 将继续执行,所以对于切换至后台的情况需要监听 App 状态,记录变化的时间。React Native 提供了 AppState 监听 App 状态改变,AppState 一共有三种状态,包括以下三种。
- active - 应用正在前台运行
- background - 应用正在后台运行。用户既可能在别的应用中,也可能在桌面
- inactive - 这是一个过渡状态,不会在正常的 React Native 应用中出现
componentDidMount() {
AppState.addEventListener('change', this._handleAppStateChange);
}
componentWillUnmount() {
AppState.removeEventListener('change', this._handleAppStateChange);
this.interval && clearInterval(this.interval);
}
_handleAppStateChange = (nextAppState) => {
if (this.state.appState === 'active' && nextAppState.match(/inactive|background/)) {
this.backgroundTime = new Date().getTime() / 1000;
}
if (this.state.appState.match(/inactive|background/) && nextAppState === 'active') {
this.backgroundTime = utils.fomatFloat(new Date().getTime() / 1000 - this.backgroundTime,0);
}
this.setState({appState: nextAppState});
}
最后完整实现代码
import React, {
PureComponent,
} from 'react';
import {
TouchableOpacity,
Text,
AppState,
StyleSheet
} from 'react-native';
function fomatFloat(src, pos) {
return Math.round(src * Math.pow(10, pos)) / Math.pow(10, pos);
}
class CountDown extends PureComponent {
constructor(props) {
super(props);
this.state = {
appState: AppState.currentState,
countdown: -1,
disabled: false
};
this.backgroundTime = 0;
}
componentDidMount() {
AppState.addEventListener('change', this._handleAppStateChange);
}
componentWillUnmount() {
AppState.removeEventListener('change', this._handleAppStateChange);
this.interval && clearInterval(this.interval);
}
_handleAppStateChange = (nextAppState) => {
if (this.state.appState === 'active' && nextAppState.match(/inactive|background/)) {
this.backgroundTime = new Date().getTime() / 1000;
}
if (this.state.appState.match(/inactive|background/) && nextAppState === 'active') {
this.backgroundTime = fomatFloat(new Date().getTime() / 1000 - this.backgroundTime,0);
}
this.setState({appState: nextAppState});
}
setCountdown(countdown) {
this.setState({
countdown: countdown
});
}
getCountdown() {
return this.state.countdown;
}
startCountDown() {
this.interval = setInterval(() => {
if (this.backgroundTime < this.getCountdown()) {
this.setState({
countdown: this.getCountdown() - this.backgroundTime - 1
},()=>{
this.backgroundTime = 0;
if (this.getCountdown() < 0) {
this.interval && clearInterval(this.interval);
}
if (this.getCountdown() >= 0) {
this.setButtonClickDisable(true);
} else {
this.setButtonClickDisable(false);
}
});
} else {
this.setCountdown(-1);
this.setButtonClickDisable(false);
this.interval && clearInterval(this.interval);
}
}, 1000);
this.setButtonClickDisable(true);
}
setButtonClickDisable(enable) {
this.setState({
disabled: enable
});
}
onPress = () => {
this.setCountdown(120);
this.startCountDown();
}
render() {
return (
<TouchableOpacity disabled={this.state.disabled} onPress={this.onPress} style={styles.vcode}>
{this.state.countdown >= 0 ?
<Text style={styles.vcodeText}>
{`${this.state.countdown}`}秒
</Text> :
<Text style={styles.vcodeText}>
获取验证码
</Text>
}
</TouchableOpacity>
);
}
}
const styles = StyleSheet.create({
vcode: {
borderRadius: 5,
borderColor: '#ccc',
borderWidth: 1,
height:40,
justifyContent: 'center',
backgroundColor:'white',
alignItems: 'center',
marginLeft: 5
},
vcodeText: {
color: 'rgba(255,165,0,1.0)',
}
});
export default CountDown;