UNPKG

react-periodical

Version:

React wrapper component for calling function periodically.

128 lines (107 loc) 2.71 kB
import React, { Component, PropTypes } from 'react'; class Periodical extends Component { static propTypes = { f: PropTypes.func.isRequired, period: PropTypes.number, limit: PropTypes.number, paused: PropTypes.bool, components: PropTypes.oneOfType( [ PropTypes.arrayOf( PropTypes.oneOfType([PropTypes.func, PropTypes.string]) ), PropTypes.oneOfType([PropTypes.func, PropTypes.string]) ] ) }; static defaultProps = { period: 1000, paused: false }; constructor(props) { super(props); this.runCount = 0; } componentDidMount() { this.start(); } shouldComponentUpdate({ f, period, limit, paused }) { return ( this.props.f !== f || this.props.period !== period || this.props.limit !== limit || this.props.paused !== paused ); } componentDidUpdate({ paused: prevPaused }) { if (prevPaused && !this.props.paused) { this.resume(); } if (!prevPaused && this.props.paused) { this.pause(); } } componentWillUnmount() { clearInterval(this.runner); this.runner = null; } run() { if (this.runner || this.runCount === 0) { this.isRunnable() ? this.props.f() : this.pause(); this.runCount = this.runCount + 1; } } start() { this.run(); this.runner = setInterval(() => this.run(), this.props.period); } pause() { clearInterval(this.runner); this.runner = null; const { limit } = this.props; if (limit && limit === this.runCount) { this.forceUpdate(); } } resume() { this.runner = setInterval(() => this.run(), this.props.period); } reset() { this.pause(); this.runCount = 0; } isRunnable() { const { limit, paused } = this.props; return (!paused && (!limit || this.runCount < limit)); } getChildren(childProps) { const { components, children } = this.props; if (components) { if (Array.isArray(components) && components.length) { return components.map((Child, i) => <Child key={i} {...childProps} />); } const Child = components; return <Child {...childProps} />; } if (children) { return React.Children.map(children, (child) => React.cloneElement(child, childProps)); } return null; } render() { const { limit } = this.props; const childProps = { runOnceHandler: () => this.props.f() }; if (limit && limit === this.runCount) { childProps['restartHandler'] = () => { this.reset(); this.start(); }; } return ( <div> {this.getChildren(childProps)} </div> ); } } export default Periodical;