简体   繁体   中英

How to render Timer without any performance issue

When user tap on particular button Timer should run to calculate how long the user performing the task. Timer should be in below format

HH : MM : SS
00 : 00 : 00

Timer should start from 0, end after 1 hour. As per my knowledge this can be achieved by using multiple state updates and setInterval , setTimeout , clearInterval . But my concern is will there be any performance issue if we run multiple state updates on continuous basis?

Is there any react-native package to achieve this? Thank You!

But my concern is will there be any performance issue if we run multiple state updates on continuous basis?

There shouldn't be, you're talking about an update every second or so, which isn't all that much.

Be sure not to trust the interval, since the actual time between when you schedule a timer and when it fires can vary widely based on what else is going on. So be sure to always calculate the time remaining from the initial start time , not an accumulation of the times you've given the timer. Eg:

timerCallback() {
    this.setState({remaining: Date.now() - this.timerStarted});
}

or similar.

Here's a very rough example of why you always recalc rather than subtracting the interval from the time remaining:

 function zeroPad(x, width) { return String(x).padStart(width, "0"); } class Time extends React.Component { render() { let time = Math.round(this.props.time / 1000); const seconds = time % 60; time -= seconds; const minutes = Math.floor(time / 60) % 60; time -= minutes * 60; const hours = Math.floor(time / 3600); return [ <span>{zeroPad(hours, 2)}</span>, ":", <span>{zeroPad(minutes, 2)}</span>, ":", <span>{zeroPad(seconds, 2)}</span> ]; } } class BadTimer extends React.Component { constructor(props) { super(props); this.interval = 1000; this.state = { running: false, remaining: 0, actualDuration: 0 }; this.start = this.start.bind(this); this.timerCallback = this.timerCallback.bind(this); } componentDidMount() { if (this.props.autoStart) { this.start(); } } start() { this.setState(({running}) => { if (!running) { this.started = Date.now(); // Just so we can show actual duration later setTimeout(this.timerCallback, this.interval); return {running: true, remaining: this.props.length}; } }); } timerCallback() { this.setState(({running, remaining}) => { if (running) { // Don't do this remaining = Math.max(remaining - this.interval, 0); if (remaining <= 500) { return {running: false, remaining, actualDuration: Date.now() - this.started}; } setTimeout(this.timerCallback, this.interval); return {remaining}; } }); } render() { const {running, remaining, actualDuration} = this.state; return ( <span> {running ? <Time time={remaining} /> : <input type="button" value="Start" onClick={this.start} />} {actualDuration ? <span> Actual duration: <Time time={actualDuration} /></span> : false} </span> ); } } class GoodTimer extends React.Component { constructor(props) { super(props); this.interval = 1000; this.state = { started: 0, update: 0, actualDuration: 0 }; this.start = this.start.bind(this); this.timerCallback = this.timerCallback.bind(this); } componentDidMount() { if (this.props.autoStart) { this.start(); } } start() { this.setState(({started, update}) => { if (!started) { setTimeout(this.timerCallback, this.interval); started = Date.now(); return {started}; } }); } timerCallback() { // Do this instead this.setState(({started, update}) => { if (started) { const remaining = this.getRemaining(started); if (remaining <= 500) { return {started: 0, actualDuration: Date.now() - started}; } setTimeout(this.timerCallback, this.interval); return {update: update + 1}; } }); } getRemaining(started) { return this.props.length - (Date.now() - started); } render() { const {started, actualDuration} = this.state; const remaining = this.getRemaining(started); return ( <span> {started ? <Time time={remaining} /> : <input type="button" value="Start" onClick={this.start} />} {actualDuration ? <span> Actual duration: <Time time={actualDuration} /></span> : false} </span> ); } } ReactDOM.render( <div> <div> <label>Bad:</label><BadTimer autoStart={true} length={15000} /> </div> <div> <label>Good:</label><GoodTimer autoStart={true} length={15000} /> </div> </div>, document.getElementById("root") ); // Throw some delays in for (let n = 3000; n < 12000; n += 3000) { setTimeout(() => { console.log("Thread is busy..."); const busy = Date.now(); setTimeout(() => { // Do something that takes some time const stop = Date.now() + (Math.random() * 2000) + 700; while (Date.now() < stop) { // Loop } console.log(`...done, was busy ${Date.now() - busy}ms`); }, 0); }, n); }
 body { font-size: 16px; } label { width: 48px; display: inline-block; }
 <div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.11.0/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM