ReactJS实现类似Online Stopwatch倒计时秒表及修复定时器值不更新问题
Fixing Your React Countdown Timer Issue
Hey there! Let's work through getting your countdown timer up and running properly, just like the tool you're referencing. I’ve looked over your code and found several key issues that are preventing the timer from updating when you trigger it, plus some missing pieces to make it functional.
Key Problems in Your Original Code
- Incorrect state type: You initialized
time2as an empty string. When you try to subtract 1 from a string, you getNaN(Not a Number), so the state never updates correctly. - Invalid condition in
componentDidUpdate: You checked forthis.state.count, butcountdoesn’t exist in your state. You meant to checktime2instead. - String concatenation in
toggle: Buildingtime2as a string means subtraction won’t work as expected—we need to handle it as a number. - Missing
rendermethod: There was no UI to display the countdown or trigger the timer controls!
Corrected Full Code
Here’s a revised version that fixes these issues and adds core functionality matching the countdown tool:
import React, { Component } from 'react'; export default class StopWatch extends Component { constructor(props) { super(props); this.state = { // Store time as a number, not a string time2: 0, // Track if the timer is running to prevent duplicate intervals isRunning: false }; // Bind methods to the component instance to fix `this` context this.timeCount = this.timeCount.bind(this); this.stopTimer = this.stopTimer.bind(this); this.toggle = this.toggle.bind(this); this.resetTimer = this.resetTimer.bind(this); } timeCount() { // Don't start a timer if it's already running if (this.state.isRunning) return; this.setState({ isRunning: true }, () => { this.time = setInterval(() => { // Use functional state update to get the latest state value this.setState(prevState => { if (prevState.time2 <= 0) { this.stopTimer(); return { time2: 0 }; } return { time2: prevState.time2 - 1 }; }); }, 1000); }); } stopTimer() { clearInterval(this.time); this.setState({ isRunning: false }); } resetTimer() { this.stopTimer(); this.setState({ time2: 0 }); } componentWillUnmount() { // Clean up the interval when the component unmounts to avoid memory leaks clearInterval(this.time); } toggle(key) { this.setState(prevState => { // Convert input to a number and build the total time const newTime = prevState.time2 * 10 + Number(key); // Limit to 6 digits (max 999999 seconds = ~277 hours) if (newTime.toString().length > 6) return prevState; return { time2: newTime }; }); } // Format seconds into HH:MM:SS for display formatTime(seconds) { const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); const remainingSeconds = seconds % 60; // Pad numbers with leading zeros for a clean look return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`; } render() { return ( <div style={{ textAlign: 'center', marginTop: '50px' }}> {/* Display formatted countdown time */} <h1 style={{ fontSize: '4rem' }}>{this.formatTime(this.state.time2)}</h1> {/* Numeric input buttons */} <div style={{ margin: '20px 0' }}> {[1,2,3,4,5,6,7,8,9,0].map(num => ( <button key={num} onClick={() => this.toggle(num)} disabled={this.state.isRunning} style={{ padding: '12px 18px', margin: '6px', fontSize: '20px', cursor: 'pointer' }} > {num} </button> ))} </div> {/* Timer control buttons */} <div> <button onClick={this.timeCount} disabled={this.state.isRunning || this.state.time2 === 0} style={{ padding: '12px 24px', margin: '0 10px', fontSize: '18px', backgroundColor: '#4CAF50', color: 'white', border: 'none', borderRadius: '4px', cursor: 'pointer' }} > Start </button> <button onClick={this.stopTimer} disabled={!this.state.isRunning} style={{ padding: '12px 24px', margin: '0 10px', fontSize: '18px', backgroundColor: '#f44336', color: 'white', border: 'none', borderRadius: '4px', cursor: 'pointer' }} > Stop </button> <button onClick={this.resetTimer} style={{ padding: '12px 24px', margin: '0 10px', fontSize: '18px', backgroundColor: '#2196F3', color: 'white', border: 'none', borderRadius: '4px', cursor: 'pointer' }} > Reset </button> </div> </div> ); } }
What Changed & Why
State Management:
time2is now a number instead of a string, so subtraction works as intended.- Added
isRunningto track timer state, preventing duplicate intervals and disabling buttons when appropriate.
Functional State Updates:
- Used
prevStatein the interval to ensure we always have the latest time value, avoiding stale state issues.
- Used
UI & Usability:
- Added a
formatTimemethod to display time in HH:MM:SS, matching the reference tool. - Added numeric input buttons and control buttons (Start/Stop/Reset) with disabled states for better UX.
- Added a
Cleanup:
- Ensured the interval is cleared in
componentWillUnmountto prevent memory leaks.
- Ensured the interval is cleared in
This code will let you input a number of seconds, start the countdown, stop it, reset it, and display the time correctly—just like the countdown tool you want to replicate.
内容的提问来源于stack exchange,提问作者vikas kumar
相关产品推荐
相关产品推荐

