我有以下代码,这是一个反应组件呈现一个巨大的组件。只要巨大的组件没有完成渲染,就会显示一个加载指示器。
import * as React from "react";
import ReactDOM from "react-dom";
import {HUGEComponent} from "./huge.tsx";
class App extends React.Component<{}, {loading: boolean}> {
constructor(props: {}) {
super(props);
this.state = {loading: true};
}
componentDidMount() {
setTimeout(() => this.setState({loading: false}), 0);
}
render() {
return this.state.loading ? <p>Loading...</p> : <HUGEComponent />;
}
}
ReactDOM.render(<App />, document.getElementById("root"));
setTimeout
内部的componentDidMount
函数确保状态更新仅在加载HUGEComponent
之后才发生(我使用10000段lorem ipsum作为HUGEComponent
)。如果没有setTimeout
,状态会立即更新,并且不会显示加载指示器。
所以我的问题是,为什么这与setTimeout
一起工作?我知道,它将状态更新推送到消息队列,因此将在所有其他内容完成后执行。但是因为使用了三元运算符(延迟求值),所以HUGEComponent
的实际渲染应该等到状态更新,以便在渲染之前进行状态更新,但这似乎不正确。只要没有评估<HUGEComponent />
,该州实际上没有更新。那么为什么<HUGEComponent />
在状态更新之前进行了评估,尽管三元运算符中存在惰性评估?
我认为你对事件的解释是错误的。实际上状态更新并不等待HugeComponent进行评估,但它会立即发生,触发重新渲染并导致HugeComponent进行评估。当HugeComponent正在评估时,你不会看到你的DOM有任何变化,所以这就是在HugeComponent评估时加载文本的原因。
对于不使用setTimeout的情况,@ tan-dat的回答是有意义的。如果未使用setTimeout,则用户将看不到中间状态(这是您的加载文本)。
也许是因为这个。
您可以在componentDidMount()中立即调用setState()。它将触发额外的渲染,但它会在浏览器更新屏幕之前发生。这保证了即使在这种情况下将调用render()两次,用户也不会看到中间状态。请谨慎使用此模式,因为它通常会导致性能问题。在大多数情况下,您应该能够在构造函数()中分配初始状态。但是,当您需要在渲染依赖于其大小或位置的内容之前测量DOM节点时,可能需要对模态和工具提示等情况进行处理。 React docs
类似的问题可以解释原因:Is setState() inside componentDidMount() considered an anti-pattern