2017-07-24 35 views
0

我ReactJS的初学者和javascript如何一次只设置一个数组元素的状态?

我问一个问题关于How can I setState on two array elements at once?

在这一问题的响应者告诉我不无论如何变异的状态。

但我还有一个问题,如果我想使用clearInterval(),当定时器到达0

在我的codePen Timer Demo 2新的尝试,停止倒计时,

我使用find()方法找到时间为0的元素,并使用clearInterval停止倒计时,但如果一个元素的时间到达0而另一个元素的时间不到,则全部停止。

我该怎么办才能修复它?

const timers = [ 
    { 
    id: 1, 
    time: 5, 
    timeIsUp: false, 
    }, 
    { 
    id: 2, 
    time: 10, 
    timeIsUp: false, 
    }, 
]; 
class Clock extends React.Component { 
    constructor(props) { 
    super(props); 
    this.state= { 
     timers, 
    } 
    this.time_controller = 0; 

    } 
    componentDidMount(){ 
    this.time_controller = setInterval(() =>{ 
     this.countDown(); 
    }, 1000) 
    } 
    countDown(){ 
    const foundTimers = this.state.timers.map(timer => ({ 
     ...timer, 
     time: timer.time-1 
    })); 
    this.setState({timers: foundTimers}); 
    const foundTimer = foundTimers.find(timer => timer.time === 0); 
    if(!!foundTimer){ 
     clearInterval(this.time_controller); 
    } 
    } 

    renderTimers(){ 
    return(
    this.state.timers.map((timer) =>{ 
     return(
     <div key = {timer.id} > 
      <div>{timer.time}</div> 
     </div> 
    ) 
    }) 
    ) 
    } 

    render() { 

    return (
     <div> 
     {this.renderTimers()} 
     </div> 
    ); 
    } 
} 

ReactDOM.render(
    <Clock />, 
    document.getElementById('root') 
); 
+0

@AndrewLi所以我需要添加time_controller到数组元素? –

回答

3

这有什么做与状态管理,这是简单的逻辑:

  1. ,直到你倒计数所有定时器不要关闭的时间间隔。
  2. 不要减少已经达到零的定时器的时间。

附注:timeIsUp标志没有任何理由,是吗? time === 0意味着时间到了,不是吗?复制状态为您在一个地方更新但不是其他地方的错误打开了大门。

东西沿着这些线路,但细节并不像概念一样重要:

countDown() { 
    let updated = false; 
    let keepTicking = false; 
    const updatedTimers = this.state.timers.map(timer => { 
    // Note that if we don't modify `timer`, we return it for reuse 
    if (timer.time > 0) { 
     timer = {...timer, time: timer.time - 1}; 
     updated = true; 
     keepTicking = timer.time > 0; 
    } 
    return timer; 
    }); 
    if (updated) { 
    // We changed somthing, update 
    this.setState({timers: updatedTimers}); 
    } 
    if (this.time_controller !== 0 && !keepTicking) { 
    // No more active timers, stop ticking 
    clearInterval(this.time_controller); 
    this.time_controller = 0; 
    } 
} 

注意,我清零定时器手柄当我们清除定时器,所以我们知道它的运行。

注意,在这个例子中,我采取了map回调与副作用(设置updatedkeepTicking标志)的务实的做法。我没有这样的局部副作用的问题,但是会有一个重大的运动。

非侧effecty版本将至少部分地循环定时器不止一次:

countDown() { 
    const timers = this.state.timers; 
    // Need to update? 
    if (timers.find(t => t.time > 0)) { 
    const updatedTimers = timers.map(timer => (
     // If we don't change a timer, we can reuse it 
     timer.time === 0 ? timer : {...timer, time: timer.time - 1} 
    ); 
    this.setState({timers: updatedTimers}); 
    } 
    // Done ticking? 
    if (this.time_controller !== 0 && updatedTimers.every(t => t.time === 0)) { 
    clearInterval(this.time_controller); 
    this.time_controller = 0; 
    } 
} 

注意代码是如何清洁(因为我们表达我们对自己做的每一件事情,只有当我们需要)但效率较低(我们可能必须努力寻找接近最终需要更新并保持滴答状态的计时器)。 90%的时间,效率并不重要,timers将会少于几千条长。所以有一个争论。

+0

如果我不关闭间隔并停止倒数,我该怎么办? –

+1

@ChamperWu:如果'time'已经是0,你就不会减少'time'。我已经添加了一些代码,但它的概念很重要。 –

+0

@ T.J.Crowder好吧,既然你已经添加了代码,我应该删除我的答案吗? – Li357

相关问题