如何一次在两个数组元素上设置setState?

时间:2017-07-22 16:53:14

标签: javascript reactjs ecmascript-6

我尝试构建一个Timer Demo App。我使用timer来自动倒计时,但我的初始状态id是一个包含2个元素的数组,我想在两个计时器上一起倒计时

在我的代码中,如果我将const timers = [ { id: 1, time: 15, }, { id: 2, time: 20, }, ]; class Clock extends React.Component { constructor(props) { super(props); this.state= { timers, } } componentDidMount(){ setInterval(() => { this.countDown(); }, 1000); } countDown(id){ const foundTimer = this.state.timers.find(timer => timer.id === id); foundTimer.time = foundTimer.time - 1; this.setState({timers: this.state.timers}); } renderTimers(){ return( this.state.timers.map((timer) =>{ console.log(timer); return( <div key = {timer.id} > <div>{timer.time}</div> </div> ) }) ) } render() { return ( <div> {this.renderTimers()} </div> ); } } 参数传递给函数(例如1或2),我可以倒计时一个元素,但我想要将每个元素统计在一起,我该怎么做呢? / p>

This is my demo in CodePen

{{1}}

2 个答案:

答案 0 :(得分:4)

使用this.state.timers修改Array#map,将原始数组元素映射到新数组元素。不要直接改变国家,它是万恶之源。例如:

countDown() {
  this.setState(prevState => ({
    timers: prevState.timers.map(timer => ({
      ...timer,
      time: timer.time - 1
    }))
  }));
}

这会将每个计时器映射到一个新的计时器,而不会改变状态,新的计时器保持相同的属性(通过object spread properties),除了它会将每个计时器的time属性更改为减去当前时间。

如果您的环境不支持对象展开属性,请改用Object.assign

this.setState(prevState => ({
  timers: prevState.timers.map(timer =>
    Object.assign(
      {},
      timer,
      { time: timer.time - 1 }
    )
  )
}));

这将完成上述相同的操作,它会将属性从timer复制到空对象{}(防止变异),然后覆盖time属性并递减它。如果您的平台不支持对象传播属性,它只是一个更详细的版本。

另外,请考虑将timers作为 a prop 传递,而不是作为类外的数组。将变量限制在最窄范围内。

答案 1 :(得分:1)

好吧首先,改变状态并不是一个好主意,它可能导致意想不到的副作用,可能会给你带来真正的头痛。从不改变国家是一种好习惯。在不改变状态的情况下实现您想要的方法可以如下:

...
countDown() {
  const newTimers = this.state.timers.map(t => Object.assign({}, t, { time: t.time - 1}));
  this.setState({ timers: newTimers });
}
...