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

Why is non-reachable part of ternary operator evaluated before state update via setTimeout?

我有以下代码,这是一个渲染巨大组件的反应组件。只要这个巨大的组件还没有完成渲染,就会显示一个加载指示器。

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"));

componentDidMount 中的 setTimeout 函数确保状态更新仅在 HUGEComponent 加载后发生(我使用了 10000 段 lorem ipsum 作为 HUGEComponent).如果没有setTimeout,状态会立即更新并且不会显示加载指示器。

所以我的问题是,为什么这对 setTimeout 有效?我知道,它将状态更新推送到消息队列,因此将在所有其他事情完成后执行。但是因为使用了三元运算符(惰性求值),所以 HUGEComponent 的实际渲染应该等到状态被更新,这样状态更新就发生在渲染它之前,但这似乎不是真的。只要 <HUGEComponent /> 还没有被评估,状态实际上就不会更新。那么,尽管在三元运算符中进行了惰性求值,为什么 <HUGEComponent /> 在状态更新之前求值?

可能是因为这个。

You may call setState() immediately in componentDidMount(). It will trigger an extra rendering, but it will happen before the browser updates the screen. This guarantees that even though the render() will be called twice in this case, the user won’t see the intermediate state. Use this pattern with caution because it often causes performance issues. In most cases, you should be able to assign the initial state in the constructor() instead. It can, however, be necessary for cases like modals and tooltips when you need to measure a DOM node before rendering something that depends on its size or position. React docs

可以解释原因的类似问题:

我认为你对事件的理解是错误的。实际上状态更新不是等待 HugeComponent 评估,而是立即发生,触发重新渲染并导致 HugeComponent 评估。当 HugeComponent 正在评估时,您不会在 DOM 中看到任何变化,因此这就是在 HugeComponent 正在评估时加载文本可见的原因。

对于不使用 setTimeout 的情况,@tan-dat 的回答是有道理的。当不使用 setTimeout 时,用户将看不到中间状态(这是您的加载文本)。