React - 如何检测父组件的所有子组件何时对用户可见?

Jas*_*enX 15 reactjs

TL; 博士

父组件如何知道其下每个子组件的渲染何时完成以及用户可见的 DOM 是最新版本?

假设我有一个由孙组件组成的component A子组件。这些孙组件中的每一个都从一个 RESTful API 端点获取数据,并在数据可用时呈现自身。Grid3x3

I would like to cover the entire area of Component A with a loader placeholder, to be unveiled only when the last of the components in the grid has fetched the data successfully, and rendered it, such that it's already on the DOM and can be viewed.

The user experience should be a super smooth transition from "loader" to a fully populated grid without flickering.

My problem is knowing exactly when to unveil the components under the loader.

Is there any mechanism I can rely on to do this with absolute accuracy? I don't to hard code a time limit for the loader. As I understand relying on ComponentDidMount for every child is also unreliable as it doesn't actually guarantee the component is fully visible to the user at the time of the call.

To distill the question even further:

我有一个呈现某种数据的组件。初始化后它没有它,所以在它componentDidMount里面它会为它点击一个 API 端点。一旦它接收到数据,它就会改变它的状态来反映它。可以理解,这会导致重新渲染该组件的最终状态。我的问题是:我怎么知道重新渲染何时发生反映在面向用户的 DOM 中。该时间点 != 组件状态已更改为包含数据的时间点。

And*_*ner 6

React 中有两个生命周期钩子,它们在组件的 DOM 呈现后被调用:

对于您的用例,当N个子组件都满足某个条件X时,您的父组件P感兴趣。X 可以定义为一个序列:

  • 异步操作完成
  • 组件已呈现

通过结合组件的状态并使用componentDidUpdate钩子,您可以知道序列何时完成以及您的组件何时满足条件 X。

您可以通过设置状态变量来跟踪异步操作何时完成。例如:

this.setState({isFetched: true})
Run Code Online (Sandbox Code Playgroud)

设置状态后,React 将调用您的组件componentDidUpdate函数。通过比较此函数中的当前和先前状态对象,您可以向父组件发出异步操作已完成且新组件的状态已呈现的信号:

componentDidUpdate(_prevProps, prevState) {
  if (this.state.isFetched === true && this.state.isFetched !== prevState.isFetched) {
    this.props.componentHasMeaningfullyUpdated()
  }
}
Run Code Online (Sandbox Code Playgroud)

在您的 P 组件中,您可以使用计数器来跟踪有多少孩子进行了有意义的更新:

function onComponentHasMeaningfullyUpdated() {
  this.setState({counter: this.state.counter + 1})
}
Run Code Online (Sandbox Code Playgroud)

最后,通过知道N的长度,您可以知道所有有意义的更新何时发生,并在P的渲染方法中采取相应的行动:

const childRenderingFinished = this.state.counter >= N
Run Code Online (Sandbox Code Playgroud)