React中使用Map实现多行独立倒计时的技术求助
Hey there! The problem with your current code is that all your car rows are sharing the same single time and seconds state, plus a single timer instance. That's why every countdown updates together instead of being independent. Let's adjust this to track each countdown separately.
Here's how to refactor your code:
Update your state structure
Instead of having globaltimeandseconds, we'll store each car's countdown data directly in thedataarray (keeping it in the data array keeps things straightforward). We'll also track multiple timers using an object instead of a single variable.Modify timer management functions
We need to makestartTimerandcountDownaccept a car ID so they know which countdown to update. We'll store timers in an object where keys are car IDs, so we can clear specific timers when needed.Adjust the addCar function
When adding a new car, initialize its countdown state (3600 seconds) and start its timer right away.
Here's the full refactored code:
class Example extends React.Component { constructor() { super(); this.state = { data: [ { "id": 1, "car": 'Audi 2018', seconds: 3600, time: {} } ] }; this.timers = {}; // Track multiple timers by car ID this.startTimer = this.startTimer.bind(this); this.countDown = this.countDown.bind(this); } secondsToTime(secs){ let hours = Math.floor(secs / (60 * 60)); let divisor_for_minutes = secs % (60 * 60); let minutes = Math.floor(divisor_for_minutes / 60); let divisor_for_seconds = divisor_for_minutes % 60; let seconds = Math.ceil(divisor_for_seconds); return { "h": hours, "m": minutes, "s": seconds }; } componentDidMount() { // Initialize time for each car and start their timers this.state.data.forEach(car => { const timeLeftVar = this.secondsToTime(car.seconds); this.setState(prevState => ({ data: prevState.data.map(item => item.id === car.id ? {...item, time: timeLeftVar} : item ) })); this.startTimer(car.id); }); } startTimer(carId) { // Only start if no timer exists for this car if (!this.timers[carId]) { this.timers[carId] = setInterval(() => this.countDown(carId), 1000); } } countDown(carId) { this.setState(prevState => { // Find the car we need to update const updatedData = prevState.data.map(item => { if (item.id === carId) { const newSeconds = item.seconds - 1; const newTime = this.secondsToTime(newSeconds); // If we hit zero, clear the timer if (newSeconds === 0) { clearInterval(this.timers[carId]); delete this.timers[carId]; } return {...item, seconds: newSeconds, time: newTime}; } return item; }); return { data: updatedData }; }); } addCar = () =>{ const newId = this.state.data.length + 1; // Simple ID generation const newCar = { "id": newId, "car": `New Car ${newId}`, seconds: 3600, time: this.secondsToTime(3600) }; this.setState(prevState=>({ data: [...prevState.data, newCar] }), () => { // Start the timer after the state updates this.startTimer(newId); }); } render() { return ( <div> {this.state.data.map(row=> <ul key={row.id}> <li> Car: {row.car} <b>Finish:</b> h: {row.time.h} m: {row.time.m} s: {row.time.s} </li> </ul> )} <button onClick={this.addCar}>Add Car</button> </div> ) } // Clean up timers when component unmounts componentWillUnmount() { Object.values(this.timers).forEach(timer => clearInterval(timer)); } }
Key changes explained:
this.timersobject: Stores individual timers for each car, using the car's ID as the key. This lets us start/stop timers for specific cars without affecting others.- Per-car state: Each car object now has its own
secondsandtimeproperties, so updates are isolated to the specific row. startTimerandcountDownacceptcarId: These functions now target a specific car instead of updating global state.- Component cleanup: Added
componentWillUnmountto clear all timers when the component is removed, preventing memory leaks.
This way, every car gets its own independent countdown that starts when the car is added, and stops when it hits zero—no more shared timers!
内容的提问来源于stack exchange,提问作者Laura delgado

