为什么在通过setTimeout更新状态之前评估三元运算符的不可访问部分?

时间:2019-03-10 14:09:57

标签: javascript reactjs settimeout jsx ternary-operator

我有以下代码,这是一个呈现巨大组件的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 />在状态更新之前进行了计算?

2 个答案:

答案 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