1. Countdown component that can be updated and also used in lists/flatlist.
Code:
import React from 'react';
import PropTypes from 'prop-types';
import { View, Text, AppState } from 'react-native';
import { translate } from '../../../helpers/Localization';
class CountDown extends React.Component {
static propTypes = {
id: PropTypes.string,
until: PropTypes.number,
onChange: PropTypes.func,
onFinish: PropTypes.func,
};
state = {
until: Math.max(this.props.until, 0),
lastUntil: null,
wentBackgroundAt: null,
};
constructor(props) {
super(props);
this.timer = setInterval(this.updateTimer, 1000);
}
componentDidMount() {
this.appStateSubscription = AppState.addEventListener(
'change',
this._handleAppStateChange,
);
}
componentWillUnmount() {
clearInterval(this.timer);
this.appStateSubscription.remove();
}
componentDidUpdate(prevProps, prevState) {
if (
this.props.until !== prevProps.until ||
this.props.id !== prevProps.id
) {
this.setState({
lastUntil: 0,
until: Math.max(this.props.until, 0),
});
}
}
_handleAppStateChange = currentAppState => {
const { until, wentBackgroundAt } = this.state;
if (
currentAppState === 'active' &&
wentBackgroundAt &&
this.props.running
) {
const diff = (Date.now() - wentBackgroundAt) / 1000.0;
this.setState({
lastUntil: until,
until: Math.max(0, until - diff),
});
}
if (currentAppState === 'background') {
this.setState({ wentBackgroundAt: Date.now() });
}
};
secondsToDhms = () => {
const { until } = this.state;
let seconds = Number(until);
var d = Math.floor(seconds / (3600 * 24));
var h = Math.floor((seconds % (3600 * 24)) / 3600);
var m = Math.floor((seconds % 3600) / 60);
var s = Math.floor(seconds % 60);
var dDisplay = d > 0 ? d + 'd ' : '';
var hDisplay = h > 0 ? h + 'h ' : d > 0 ? '12h ' : '';
var mDisplay = m > 0 ? m + 'm ' : h > 0 ? '60m ' : '';
var sDisplay = s > 0 ? s + 's ' : m > 0 ? '60s' : '';
return dDisplay + hDisplay + mDisplay + sDisplay;
};
updateTimer = () => {
if (this.state.lastUntil === this.state.until || !this.props.running) {
return;
}
if (
this.state.until === 1 ||
(this.state.until === 0 && this.state.lastUntil !== 1)
) {
if (this.props.onFinish) {
this.props.onFinish();
}
if (this.props.onChange) {
this.props.onChange(this.state.until);
}
}
if (this.state.until === 0) {
this.setState({ lastUntil: 0, until: 0 });
} else {
if (this.props.onChange) {
this.props.onChange(this.state.until);
}
this.setState({
lastUntil: this.state.until,
until: Math.max(0, this.state.until - 1),
});
}
};
renderCountDown = () => {
return (
<Text style={this.props.textStyle}>
{this.secondsToDhms() || translate('timeOver')}
</Text>
);
};
render() {
return <View style={this.props.style}>{this.renderCountDown()}</View>;
}
}
CountDown.defaultProps = {
until: 0,
size: 15,
running: true,
};
export default CountDown;
USAGE
<CountdownComponent
until={moment(item?.time_left).diff(
moment(),
'seconds',
)}
textStyle={styles.timerTextAHL}
/>
2. Countdown component using hooks:
/**
* CountDownTimer Component
*/
import moment from 'moment';
import React, {
useState,
useEffect,
useRef,
forwardRef,
useImperativeHandle,
} from 'react';
import {Text, View} from 'react-native';
import {strings} from '../../i18n';
const CountDownTimer = forwardRef((props, ref) => {
// For Total seconds
const [timeStamp, setTimeStamp] = useState(
props.timestamp ? props.timestamp : 0,
);
// Delay Required
const [delay] = useState(props.delay ? props.delay : 1000);
// For days, hours, minutes and seconds
const [, setDays] = useState(props.days ? props.days : 0);
const [, setHours] = useState(props.hours ? props.hours : 0);
const [, setMinutes] = useState(props.minutes ? props.minutes : 0);
const [, setSeconds] = useState(props.seconds ? props.seconds : 0);
// Flag for informing parent component when timer is over
const [sendOnce, setSendOnce] = useState(true);
// Flag for final display time format
const [finalDisplayTime, setFinalDisplayTime] = useState('');
const formatTime = time => {
return String(time).padStart(2, '0');
};
useInterval(() => {
if (timeStamp > 0) {
setTimeStamp(moment(props.endDate).diff(moment(), 'seconds'));
} else if (sendOnce) {
if (props.timerCallback) {
props.timerCallback(true);
} else {
console.log('Please pass a callback function...');
}
setSendOnce(false);
}
let secondsLeft = Number(timeStamp);
let d = Math.floor(secondsLeft / (3600 * 24));
let h = Math.floor((secondsLeft % (3600 * 24)) / 3600);
let m = Math.floor((secondsLeft % 3600) / 60);
let s = Math.floor(secondsLeft % 60);
let dDisplay = d > 0 ? d + strings('timeShortForm.timeDays') + ' ' : '';
let hDisplay = h > 0 ? h + strings('timeShortForm.timHrs') + ' ' : '';
let mDisplay =
m > 0
? formatTime(m) + strings('timeShortForm.timeMin') + ' '
: h > 0
? '00' + strings('timeShortForm.timeMin') + ' '
: '';
let sDisplay =
s > 0
? formatTime(s) + strings('timeShortForm.timeSec') + ' '
: m > 0
? '00' + strings('timeShortForm.timeSec') + ' '
: '';
// setDays(d);
// setHours(h);
// setMinutes(m);
// setSeconds(s);
if (dDisplay?.length) {
setFinalDisplayTime(dDisplay + hDisplay + mDisplay);
} else {
setFinalDisplayTime(hDisplay + mDisplay + sDisplay);
}
}, delay);
const refTimer = useRef();
useImperativeHandle(ref, () => ({
resetTimer: () => {
// Clearing days, hours, minutes and seconds
setDays(props.days);
setHours(props.hours);
setMinutes(props.minutes);
setSeconds(props.seconds);
// Clearing Timestamp
setTimeStamp(props.timestamp);
setSendOnce(true);
},
}));
return !finalDisplayTime ? null : (
<View ref={refTimer} style={props.containerStyle}>
<Text style={props.textStyle}>
{props.preText
? props.preText + ' ' + finalDisplayTime
: finalDisplayTime}
</Text>
</View>
);
});
function useInterval(callback, delay) {
const savedCallback = useRef();
// Remember the latest function.
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
// Set up the interval.
useEffect(() => {
function tick() {
savedCallback.current();
}
if (delay !== null) {
const id = setInterval(tick, delay);
return () => {
clearInterval(id);
};
}
}, [delay]);
}
export default CountDownTimer;
Usage:
const refTimer = useRef();
<CountdownComponent
ref={refTimer}
timestamp={moment(endDate).diff(moment(), 'seconds')}
endDate={endDate}
textStyle={styles.timingHeader}
timerCallback={onPress}
/>
Top comments (0)