繁体   English   中英

我如何一次只对一个数组元素设置状态?

[英]How can I setState on just one array element at once?

我是ReactJS和javascript的初学者

我有一个问题,关于如何一次在两个数组元素上设置状态?

在那个问题上,响应者告诉我无论如何都不要改变状态。

但是我还有另一个问题,如果我想通过使用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')
);

这与状态管理无关,它的逻辑很简单:

  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标志)。 我没有像这样的局部副作用的问题,但是有很大的动作可以解决。

非副作用版本将至少部分循环计时器一次以上:

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长度将少于几千个条目。 所以有一个论点。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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