2017-10-21 164 views
0

我想建立一個網絡應用程序,計算每天應該爲未來旅行節省多少錢(我知道它可以很容易地通過一個簡單的計算器來完成,但這是爲學習的緣故)。反應:狀態不是實時渲染

我的問題是,當我在兩個輸入中輸入成本和時間時,日常儲蓄計算不會實時呈現在DOM上。

這裏是會發生什麼:

  1. I型在第一輸入(成本要素內)成本和留在第二輸入的天數(的timeleft組件內)
  2. 的DOM使兩者的成本而留在我鍵入時(在{this.state.totalCost}{this.state.timeLeft}
  3. 的計算結果{this.state.dailyCost}呈現了「一個變」延遲(即成本= 100 = 10 我需要輸入一些東西剩下的天實時天否則像添加一個0的成本爲10在DOM中渲染爲正確的結果的計算。)

謝謝你的幫助!我希望我以一種可以理解的方式解釋。

我的代碼:

class App extends Component { 
    constructor() { 
    super(); 
    this.state = { 
     totalCost: 0, 
     timeLeft: 0, 
     dailyCost: 0, 
    } 
    } 

    updateDailySavings() { 
    if (this.state.timeLeft !== 0) { 
     this.setState({dailyCost: (this.state.totalCost/this.state.timeLeft).toFixed(2)}); 
    } else { 
     this.setState({dailyCost: 0}); 
    } 
    } 

    changeCost(newCost) { 
    this.setState({totalCost: Math.round(newCost)}); 
    this.updateDailySavings() 
    } 

    changeTimeLeft(newTimeLeft) { 
    this.setState({timeLeft: Math.round(newTimeLeft)}); 
    this.updateDailySavings() 
    } 

    render() { 
    return (
     <div className="App"> 
     <header className="App-header"> 
      <h1 className="App-title">Welcome to React</h1> 
     </header> 
     <Cost changeCost={this.changeCost.bind(this)}/> 
     <TimeLeft changeTimeLeft={this.changeTimeLeft.bind(this)}/> <br/> 
     <div>You have to save £{this.state.totalCost} in the next {this.state.timeLeft} days.<br/> 
     You have to save £{this.state.dailyCost} per day. 
     </div> 
     </div> 
    ); 
    } 
} 
+2

'setState'是異步的。如果您需要立即使用狀態值,則應該使用回調。 'this.setState({some:'value'},()=> {/ * .. doSometing .. * /})' – bennygenel

回答

1

你onChange處理函數應該是

changeCost(newCost) { 
    this.setState({totalCost: Math.round(newCost)}, 
        this.updateDailySavings); 
    } 

    changeTimeLeft(newTimeLeft) { 
    this.setState({timeLeft: Math.round(newTimeLeft)}, 
        this.updateDailySavings); 
    } 

docs

的setState()不總是立即更新組件。它可能會批處理或推遲更新,直到稍後。這使得在調用setState()之後立即讀取this.state是一個潛在的缺陷。相反,使用componentDidUpdate或setState回調函數(setState(updater,callback)),其中的任何一個在應用更新後都會保證​​觸發。

由於您希望在下一次setState調用中使用更新後的狀態,您應該使用回調。

編輯:糾正代碼刪除多餘()由@bennygenel

+1

'this.updateDailySavings()'應該是'this.updateDailySavings'。代碼呈現時,您沒有傳遞正在執行的函數。 – bennygenel

+0

感謝您的幫助。我試過這個,但不幸的是它導致了相同的行爲。 編輯:在刪除()後this.updateDailySavings它完美的工作!非常感謝你palsrealm和bennygenel! – krimou32

0

正如指出的@bennygenel指出後的setState是異步,所以你應該做的:

updateDailySavings() { 
    if (this.timeLeft !== 0) { 
     this.setState({dailyCost: (this.totalCost/this.timeLeft).toFixed(2)}); 
    } else { 
     this.setState({dailyCost: 0}); 
    } 
    } 

    changeCost(newCost) { 
    this.totalCost = Math.round(newCost); 
    this.setState({totalCost: this.totalCost}); 
    this.updateDailySavings() 
    } 

    changeTimeLeft(newTimeLeft) { 
    this.timeLeft = Math.round(newTimeLeft); 
    this.setState({timeLeft: this.timeLeft}); 
    this.updateDailySavings() 
    } 

*請注意也許兩個後來的setStates不再需要,但我不知道你是否使用它們後

+0

它的工作原理!它還不完美,有時計算返回一個錯誤的數字(即,如果在每天輸入中沒有任何東西呈現0),則成本= 100,剩餘時間= 1。但它是99%的功能!非常感謝:) – krimou32

+0

對不起,我想我忘了初始化this.timeLeft和this.totalCost。你應該試試 – 2017-10-21 21:04:07

1

計算不呈現在重新一段時間在DOM上。

一)setStateasynchronous,在同一個更新週期將覆蓋以前的更新後續調用,並且之前的更改將丟失。

所以如果你想使用this.setState值,你應該使用回調函數。

this.setState({value: 'value'},() => {return : /*something here ..*/}); 

相反變異狀態(this.state.someValue)直接的一個很好的做法,以恢復狀態的一個新的副本。

return { ...previousState, value: updated new state }; 

你可以閱讀更多Here