我有以下代码,这是一个呈现巨大组件的react组件。只要巨大的组件尚未完成渲染,就会显示加载指示器。
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 />
在状态更新之前进行了计算?
答案 0 :(得分:1)
我认为您对事件的解释是错误的。实际上,状态更新不是在等待HugeComponent评估,而是立即发生,这会触发重新渲染并导致HugeComponent评估。在HugeComponent进行评估时,您不会在DOM中看到任何变化,因此这使得在HugeComponent进行评估时可见加载文本。
对于不使用setTimeout的情况,@ tan-dat的答案很有意义。不使用setTimeout时,用户将看不到中间状态(这是您的加载文本)。
答案 1 :(得分:0)
也许是因为这个原因。
您可以立即在componentDidMount()中调用setState()。它会触发额外的渲染,但是会在浏览器更新屏幕之前发生。这样可以保证即使在这种情况下render()将被调用两次,用户也不会看到中间状态。请谨慎使用此模式,因为它经常会导致性能问题。在大多数情况下,您应该可以改为在Constructor()中分配初始状态。但是,在模态和工具提示之类的情况下,当您需要在渲染取决于其大小或位置的对象之前测量DOM节点时,可能是必需的。 React docs
一个类似的问题可以解释原因:Is setState() inside componentDidMount() considered an anti-pattern