反应:状态不实时渲染

时间:2017-10-21 19:56:59

标签: javascript reactjs react-redux

我正在尝试构建一个网络应用程序,计算每天应该为未来的旅行节省多少钱(我知道它可以通过一个简单的计算器轻松完成,但这是为了学习)。

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

以下是发生的事情:

  1. 我在第一个输入(在Cost组件中)输入成本,在第二个输入中输入剩余天数(在TimeLeft组件中)
  2. 当我输入{this.state.totalCost}{this.state.timeLeft}
  3. 时,DOM会实时显示费用和剩余时间
  4. 计算结果{this.state.dailyCost} 呈现"一次更改"延迟(即成本= 100,剩余天数= 10. 我需要输入其他内容,例如在成本中添加0以在DOM中呈现作为正确结果的计算。)
  5. 感谢您的帮助!我希望我以一种可以理解的方式解释。

    我的代码:

        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>
        );
      }
    }
    

4 个答案:

答案 0 :(得分:2)

你的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(更新程序,回调)),其中任何一个都保证在应用更新后触发。

由于您希望在下一个setState调用中使用更新状态,因此应使用回调。

编辑:在删除@bennygenel指出的额外()后更正了代码

答案 1 :(得分:1)

  

计算不会在DOM上实时呈现。

a)setStateasynchronous,同一更新周期中的后续调用将覆盖以前的更新,之前的更改将会丢失。

因此,如果您想使用this.setState值,则应使用回调函数。

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

不是直接改变状态(this.state.someValue),而是返回状态的新副本。

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

您可以阅读更多Here

答案 2 :(得分: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,但我不知道你是否在使用它们之后

答案 3 :(得分:0)

对我来说,我使用了异步等待功能,并且工作得很好

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()
  }

我希望它能为您提供帮助