2017-10-21 114 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