Skip to content

Commit c641f11

Browse files
committed
Add AppState changes handler.
1 parent e8a0250 commit c641f11

3 files changed

Lines changed: 37 additions & 20 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
[![npm](https://img.shields.io/npm/dm/rn-countdown.svg)](https://www.npmjs.com/package/rn-countdown)
55
[![npm](https://img.shields.io/npm/l/rn-countdown.svg)](https://github.com/ljunb/rn-countdown/blob/master/LICENSE)
66

7-
A smart countdown component for react-native apps. You may use it to handle different status when request a verification code. Supports custom styles in the countdown different status.
7+
A countdown component for react-native APPs. When the AppState changes to `inactive`, the timer is cleared and the new timer is turned on when the state changes back to `active`. You should use this component to request a verification code that supports custom styles for different status.
88

99
## Preview
1010
![demo](https://github.com/ljunb/screenshots/blob/master/rn-countdown.gif)

index.js

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
2-
* A smart countdown component for react-native apps. You may use it to handle different status when request a verification code.
2+
* A smart countdown component for react-native apps.
3+
* You may use it to handle different status when request a verification code.
34
* https://github.com/ljunb/react-native-countdown/
45
* Released under the MIT license
56
* Copyright (c) 2017 ljunb <cookiejlim@gmail.com>
@@ -10,7 +11,8 @@ import {
1011
StyleSheet,
1112
Text,
1213
TouchableOpacity,
13-
ViewPropTypes
14+
ViewPropTypes,
15+
AppState
1416
} from 'react-native';
1517

1618
/**
@@ -31,40 +33,37 @@ export default class Countdown extends Component {
3133
title: PropTypes.string,
3234
time: PropTypes.number,
3335
overTitle: PropTypes.string,
34-
titleStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.number]),
36+
titleStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.number, PropTypes.array]),
3537
countingStyle: ViewPropTypes.style,
3638
countingTitleTemplate: PropTypes.string,
37-
countingTitleStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.number]),
39+
countingTitleStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.number, PropTypes.array]),
3840
shouldHandleBeforeCountdown: PropTypes.func
3941
};
4042

4143
static defaultProps = {
4244
title: '获取短信验证码',
4345
time: 30,
44-
countingTitleTemplate: '{time}s后重新获取',
4546
overTitle: '重新获取',
47+
countingTitleTemplate: '{time}s后重新获取',
4648
shouldHandleBeforeCountdown: () => true
4749
};
4850

4951
constructor(props) {
5052
super(props);
53+
this.recodTime = 0;
5154
this.state = {
5255
second: props.time,
5356
status: CountdownStatus.None
5457
}
5558
}
5659

57-
shouldComponentUpdate(nextProps, nextState) {
58-
const {time, title, overTitle, countingTitleTemplate} = this.props;
59-
const {second, status} = this.state;
60-
61-
const isNewComp = nextProps.title !== title || nextProps.time !== time || nextProps.overTitle !== overTitle || nextProps.countingTitleTemplate !== countingTitleTemplate;
62-
const isCounting = nextState.second !== second || nextState.status !== status;
63-
return isNewComp || isCounting;
60+
componentDidMount() {
61+
AppState.addEventListener('change', this.handleAppState);
6462
}
6563

6664
componentWillUnmount() {
6765
this.clearTimer();
66+
AppState.removeEventListener('change', this.handleAppState);
6867
}
6968

7069
stopCountdown = () => {
@@ -74,16 +73,34 @@ export default class Countdown extends Component {
7473
}, this.clearTimer);
7574
};
7675

76+
handleAppState = nextAppState => {
77+
if (nextAppState === 'inactive') {
78+
this.recodTime = new Date();
79+
this.clearTimer();
80+
} else if (nextAppState === 'active') {
81+
if (this.state.status !== CountdownStatus.Counting) return;
82+
83+
const now = new Date();
84+
const diff = Math.round((now - this.recodTime) / 1000);
85+
if (this.state.second - diff <= 0) {
86+
this.setState({status: CountdownStatus.Over, second: this.props.time});
87+
} else {
88+
this.setState({
89+
status: CountdownStatus.Counting,
90+
second: this.state.second - diff
91+
}, this.startTimer)
92+
}
93+
}
94+
};
95+
7796
handlePress = () => {
7897
const {shouldHandleBeforeCountdown, countingTitleTemplate} = this.props;
79-
const {status} = this.state;
80-
8198
const canStartTimer = shouldHandleBeforeCountdown();
82-
if (status === CountdownStatus.Counting || !canStartTimer) return;
83-
if (countingTitleTemplate.indexOf('{time}') === -1) {
84-
console.warn('[rn-countdown] The countingTitleTemplate string must conform to the format that contain `{time}`!');
85-
}
99+
if (!canStartTimer) return;
86100
this.setState({status: CountdownStatus.Counting}, this.startTimer);
101+
102+
const showWarn = countingTitleTemplate.indexOf('{time}') === -1;
103+
showWarn && console.warn('[rn-countdown] The countingTitleTemplate string must conform to the format that contain `{time}`!');
87104
};
88105

89106
startTimer = () => {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "rn-countdown",
3-
"version": "0.0.4",
3+
"version": "0.0.5",
44
"description": "A smart countdown component for react-native apps. You may use it to handle different status when request a verification code.",
55
"main": "index.js",
66
"scripts": {

0 commit comments

Comments
 (0)