2016-11-09 216 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問題本身,但是其他的東西是組件的屬性而不是它的狀態或道具? (除了方法) –