2016-11-09 212 views
4

我在React组件中有一个使用setInterval()的计时器,我不确定最佳实践是如何使用state来启动和停止此间隔。我遇到了一些异步问题。setInterval和React中的setState

比方说,我有一组链接在渲染和罚款执行回调我的阵营组成:

let links = [10, 50, 100, 500, 1000].map((num) => { 
    return(
    <Link key={num} onClick={(e) => this.switchNums(num)} to={`/somePath/${num}`}>{num}</Link> 
) 
}) 

这里的switchNums()功能,在这里我希望它重置现有的计时器:

switchNums(num){ 
    this.stopTimer() 
    this.reset(num) 
} 

这里的startTimer()stopTimer()reset()

startTimer(){ 
    if(!this.state.timerId){  
    let timerId = setInterval(()=>{ 
     let timer = this.state.timer + 1 
     this.setState({ 
     timer: timer, 
     timerId: timerId 
     }) 
    }, 1000) 
    } 
} 

stopTimer(){ 
    clearInterval(this.state.timerId)  
    this.setState({timerId:null}) 
} 

reset(size){ 
    this.setState({ 
    gameOver: false, 
    counter: 0, 
    correct: 0, 
    numbers: this.getRandomNumbers(size), 
    timer: 0 
    }, this.startTimer()) 
} 

尽管startTimer()中有if条件,但其中一个错误是快速点击链接将导致多个间隔点火。我猜这与setState()的异步性质有关。另一个错误(我认为是相关的)是,当我慢点击时,它只会在其他时间开始间隔。

谁能一些线索呢?或者他们已经做了什么来避免异步问题setStatesetInterval(任何方式设置状态可以返回承诺吗?)一起使用,或者哪种生命周期方法最适合这种类型的情况?

回答

3

我认为这里最大的缺陷是您使用state来存储您的间隔。虽然技术上可行,但我没有看到你真的想要这样做的理由。

相反,只使用一个局部变量您的组件:

startTimer(){ 
    if(!this.timerId){  
    this.timerId = setInterval(()=>{ 
     //your function 
    }, 1000); 
    } 
} 

stopTimer(){ 
    clearInterval(this.timerId); 
} 

所以我不认为你需要使用state都在这里为您定时器。您的帖子中还有其他一些常见问题,虽然这些问题与state有关,我会尝试回答下面的问题。请记住,它们在解决您的特定问题时无关紧要。


他们有什么做了规避异步问题与setState()

state已被设置后,您可以使用回调来执行代码。这里有一个section of the official docs;这就是它说的:

第二个参数是一个可选的回调函数,一旦setState完成并且组件被重新渲染,将会执行该函数。

setState(nextState, callback); 

哪个生命周期的方法将是最适合这种类型的情况?

如上DOC的相同部分继续:

一般来说,我们建议使用componentDidUpdate()这样的逻辑来代替。

如果你的函数中有多个setState,并且你想在特定事件之后执行特定的代码,我认为你使用回调很好。为了更通用的目的,使用上面的生命周期方法。

+1

我的天啊,你可以把东西存储在组件本身中......谢谢!要试试 –

+0

当然。让我知道它是否有效。 – Chris

+0

非常感谢你!这工作完美。所以这可能是另一个SO问题本身,但是其他的东西是组件的属性而不是它的状态或道具? (除了方法) –