为什么我的 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
命令更新状态
在此 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
命令更新状态