Javascript 反应:状态未实时渲染

Javascript 反应:状态未实时渲染,javascript,reactjs,react-redux,Javascript,Reactjs,React Redux,我正在尝试建立一个网络应用程序,计算一个人每天应该为未来的旅行节省多少钱(我知道这可以很容易地用一个简单的计算器完成,但这是为了学习) 我的问题是,当我在两个输入中键入剩余的成本和时间时,每日节省量计算不会在DOM上实时呈现 发生的情况如下: 我在第一个输入中键入成本(在成本组成部分内),在第二个输入中键入剩余天数(在时间间隔组成部分内) DOM在我键入时实时呈现成本和剩余天数(在{this.state.totalCost}和{this.state.timeLeft} 计算结果{this.sta

我正在尝试建立一个网络应用程序,计算一个人每天应该为未来的旅行节省多少钱(我知道这可以很容易地用一个简单的计算器完成,但这是为了学习)

我的问题是,当我在两个输入中键入剩余的成本和时间时,每日节省量计算不会在DOM上实时呈现

发生的情况如下:

  • 我在第一个输入中键入成本(在成本组成部分内),在第二个输入中键入剩余天数(在时间间隔组成部分内)
  • DOM在我键入时实时呈现成本和剩余天数(在
    {this.state.totalCost}
    {this.state.timeLeft}
  • 计算结果{this.state.dailyCost}以“一次更改”延迟进行渲染(即成本=100,剩余天数=10。我需要键入其他内容,如在成本中添加0,以便在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>
        );
      }
    }
    
    类应用程序扩展组件{
    构造函数(){
    超级();
    此.state={
    总成本:0,
    时间限制:0,
    每日成本:0,
    }
    }
    updateDailySavings(){
    if(this.state.timeLeft!==0){
    this.setState({dailyCost:{this.state.totalCost/this.state.timeLeft.toFixed(2)});
    }否则{
    this.setState({dailyCost:0});
    }
    }
    变更成本(新成本){
    this.setState({totalCost:Math.round(newCost)});
    this.updateDailySavings()
    }
    changeTimeLeft(newTimeLeft){
    this.setState({timeLeft:Math.round(newTimeLeft)});
    this.updateDailySavings()
    }
    render(){
    返回(
    欢迎反应
    
    您必须在接下来的{this.state.timeLeft}天内保存{this.state.totalCost}。
    您必须每天保存{this.state.dailyCost}。 ); } }
    您的onChange处理程序函数应该是

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

    setState()并不总是立即更新组件。它可能会批处理更新或将更新推迟到以后。这使得在调用setState()后立即读取This.state成为一个潜在的陷阱。相反,请使用componentDidUpdate或setState回调(setState(更新程序,回调)),其中任何一个都保证在应用更新后触发

    因为您希望在下一次setState调用中使用更新的状态,所以应该使用回调


    编辑:删除额外的
    ()
    后更正了代码,正如@bennygenel所指出的那样,

    正如@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()
      }
    
    *请注意,可能以后不再需要这两个setstate,但我不知道您是否在以后使用它们

    计算不会在DOM上实时呈现

    a)
    setState
    is,同一更新周期中的后续调用将覆盖以前的更新,并且以前的更改将丢失

    因此,如果要使用
    this.setState
    值,应该使用回调函数

    this.setState({value: 'value'},() => {return : /*something here ..*/});
    
    与其直接改变状态(
    this.state.someValue
    ),不如返回状态的新副本

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

    您可以为我阅读更多内容,我使用了async await,工作得很好

    async updateDailySavings() {
        if (this.state.timeLeft !== 0) {
          await this.setState({dailyCost: (this.state.totalCost / this.state.timeLeft).toFixed(2)});
        } else {
          await this.setState({dailyCost: 0});
        }
      }
    
      async changeCost(newCost) {
        await this.setState({totalCost: Math.round(newCost)});
        this.updateDailySavings()
      }
    
      async changeTimeLeft(newTimeLeft) {
        await this.setState({timeLeft: Math.round(newTimeLeft)});
        this.updateDailySavings()
      }
    
    

    我希望它能帮助您

    设置状态
    是异步的。如果需要立即使用状态值,则应该使用回调
    this.setState({some:'value'},()=>{/*…doSometing..*/})
    this.updateDailySavings()
    应该是
    this.updateDailySavings
    。当代码呈现时,您没有传递正在执行的函数。谢谢您的帮助。我试过了,但不幸的是,结果还是一样。。编辑:删除this.updateDailySavings之后的()后,它工作得非常好!非常感谢你和bennygenel!它起作用了!它还不是完美的,有时计算返回一个错误的数字(即,在输入DailCost中没有任何内容后,如果成本=100,剩余时间=1,则呈现0)。但它99%的功能!非常感谢:)对不起,我想我忘了初始化这个.timeLeft和这个.totalCost。你应该试试