为什么我的 React 应用程序中的 console.logs 和 UI 不显示相同的状态变量?

Why do the console.logs and UI in my React app not show the same state variable?

在此 coin flipping program 中,更新的 state.flipResult 和 state.coinURL 变量打印到控制台时存在延迟(它们总是比 UI).

我确定这与 setState 更新是异步的有关。那么,我如何“强制”状态更新并重新渲染?

例如,我见过将 prevState 传递给 setState 函数以强制更新计数器的示例,但在这种情况下,flipResult 和 coinURL(“heads”或“tails”)不是基于之前的状态。我可以找到一种使用 prevState 在正面和反面之间切换的方法,但我将来可能还希望根据用户的输入或选择“强制”进行与先前状态无关的即时状态更新。有办法吗?

非常感谢您的帮助!

代码如下:

import React, { Component } from "react";

import "./styles.css";

class App extends Component {
  state = {
    flipResult: "",
    coinURL: ""
  };

  flipCoin = () => {
    let number = Math.floor(Math.random() * 100) + 1;

    if (number <= 50) {
      this.setState( { flipResult: "heads", coinURL: "heads" });
    } else if (number >= 51) {
      this.setState({ flipResult: "tails", coinURL: "tails" });
    }
    console.log("flipResult is " + this.state.flipResult);
    console.log("flipResult is " + this.state.coinURL);
  };

  render() {
    return (
      <div>
       <h2> Flip a coin! </h2>
        <br />
        <button onClick={this.flipCoin}> Flip! </button>
        <br />

        {this.state.flipResult ? (
          <div>
            The result is {this.state.flipResult}.
            <br />
            <br />
            <img
              src={`./img/${this.state.coinURL}.jpg`}
              alt="coin"
              style={{ width: "200px", height: "auto" }}
            />
          </div>
        ) : (
          <div> No result yet! </div>
        )}
      </div>
    );
  }
}

export default App;


可在此处找到 Web 应用程序 - https://codesandbox.io/s/flipcoin-zj9sl?file=/src/App.js

setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall. Instead, use componentDidUpdate or a setState callback (setState(updater, callback)), either of which are guaranteed to fire after the update has been applied

所以你可以像这样把控制台日志放在回调中:

  this.setState({ flipResult: "heads", coinURL: "heads" }, () => {
    console.log("flipResult is " + this.state.flipResult);
  });

问题是您不了解 setState 是一个异步事件,因此您不能相信调用 console.log(this.state.SOMETHING) 会给您新的状态。

函数 setState 接受回调函数作为第二个参数,因此您可以这样做:

flipCoin = () => {
    let number = Math.floor(Math.random() * 100) + 1;

    if (number <= 50) {
      this.setState( { flipResult: "heads", coinURL: "heads" }, this.logInformation);
    } else if (number >= 51) {
      this.setState({ flipResult: "tails", coinURL: "tails" }, this.logInformation);
    }
    
};

logInformation(){
  console.log("flipResult is " + this.state.flipResult);
  console.log("flipCoin is " + this.state.coinURL);
} 

因此在设置状态后,它将调用您的函数,您将能够看到新状态。

注意: 请注意,当您第一次单击时它显示为空,第二次单击时它将显示之前的状态,这是因为正如我所解释的,它显示的是未设置的值。

您发布的完整代码如下:

import React, { Component } from "react";

import "./styles.css";

class App extends Component {
  state = {
    flipResult: "",
    coinURL: ""
  };

  flipCoin = () => {
    let number = Math.floor(Math.random() * 100) + 1;

    if (number <= 50) {
      this.setState( { flipResult: "heads", coinURL: "heads" }, this.logInformation);
    } else if (number >= 51) {
      this.setState({ flipResult: "tails", coinURL: "tails" }, this.logInformation);
    }
    
  };

  logInformation(){
    console.log("flipResult is " + this.state.flipResult);
    console.log("flipCoin is " + this.state.coinURL);
  }

  render() {
    return (
      <div>
       <h2> Flip a coin! </h2>
        <br />
        <button onClick={this.flipCoin}> Flip! </button>
        <br />

        {this.state.flipResult ? (
          <div>
            The result is {this.state.flipResult}.
            <br />
            <br />
            <img
              src={`./img/${this.state.coinURL}.jpg`}
              alt="coin"
              style={{ width: "200px", height: "auto" }}
            />
          </div>
        ) : (
          <div> No result yet! </div>
        )}
      </div>
    );
  }
}

export default App;

import React, { Component } from "react";

import "./styles.css";

class App extends Component {
  state = {
    flipResult: "",
    coinURL: ""
  };

  flipCoin = async () => {
    let number = Math.floor(Math.random() * 100) + 1;

    if (number <= 50) {
      await this.setState( { flipResult: "heads", coinURL: "heads" });
    } else if (number >= 51) {
      await this.setState({ flipResult: "tails", coinURL: "tails" });
    }
    console.log("flipResult is " + this.state.flipResult);
    console.log("flipcoin png  is " + this.state.coinURL);
  };

  render() {
    return (
      <div>
       <h2> Flip a coin! </h2>
        <br />
        <button onClick={this.flipCoin}> Flip! </button>
        <br />

        {this.state.flipResult ? (
          <div>
            The result is {this.state.flipResult}.
            <br />
            <br />
            <img
              src={`./img/${this.state.coinURL}.jpg`}
              alt="coin"
              style={{ width: "200px", height: "auto" }}
            />
          </div>
        ) : (
          <div> No result yet! </div>
        )}
      </div>
    );
  }
}

export default App;



我做了什么

因为更新状态是一个异步过程,所以我们可以让父函数异步并等待通过 await 命令更新状态