Files
remark42/frontend/app/components/countdown/index.tsx
T
2019-04-28 19:27:36 +03:00

60 lines
1.5 KiB
TypeScript

/** @jsx h */
import { h, Component, RenderableProps } from 'preact';
import { exclude } from '@app/utils/exclude';
type Props = {
time: Date;
onTimePassed?: () => void;
} & JSX.HTMLAttributes;
interface State {
/** props.time converted to timestamp */
time: number;
}
/** Component which uses plain DOM mutation instead of rerendering react reactive reactivity */
export default class Countdown extends Component<Props, State> {
elemRef?: HTMLSpanElement;
intervalID?: number;
constructor(props: Props) {
super(props);
this.state = {
time: props.time.getTime(),
};
}
componentDidMount() {
this.start();
}
componentWillReceiveProps(nextProps: Props) {
if (nextProps.time === this.props.time) return;
this.setState({
time: nextProps.time.getTime(),
});
this.start();
}
shouldComponentUpdate() {
return false;
}
tick() {
if (this.elemRef) {
const value = Math.max(0, (this.state.time - new Date().getTime()) / 1000).toFixed(0);
this.elemRef!.innerText = value;
if (value === '0') {
this.props.onTimePassed && this.props.onTimePassed();
window.clearInterval(this.intervalID);
this.intervalID = undefined;
}
}
}
start() {
if (this.intervalID) clearInterval(this.intervalID);
this.tick();
this.intervalID = window.setInterval(() => {
this.tick();
}, 1000);
}
render(props: RenderableProps<Props>) {
return <span {...exclude(props, 'time', 'onTimePassed')} ref={ref => (this.elemRef = ref)} />;
}
}