React - How to detect when all sub-components of a parent component are visible to the user?
Answer a question
TL;DR
How can a parent component know when the rendering of every child component under it has finished and the DOM visible to the user with its most up to date version?
Let's say I have a component A that has a child Grid component consisting of 3x3 grandchild components. Each of those grandchild components fetches data from a restful API endpoint and renders itself when the data becomes available.
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:
I have a component that renders some kind of data. After it's initialized it doesn't have it, so in its
componentDidMountit hits an API endpoint for it. Once it receives the data, it's changing its state to reflect it. This understandably causes a re-render of the final state of that component. My question is this: How do I know when that re-render has taken place and is reflected in the User facing DOM. That point in time != the point in time when the component's state has changed to contain data.
Answers
There are two lifecycle hooks in React that are called after a component's DOM has rendered:
- componentDidMount
- componentDidUpdate (you're interested in this one)
For your use case your parent component P is interested when N child components have each satisfied some condition X. X can be defined as a sequence:
- async operation completed
- component has rendered
By combining the state of the component and using the componentDidUpdate hook, you can know when the sequence has completed and your component meets condition X.
You can keep track of when your async operation has completed by setting a state variable. For example:
this.setState({isFetched: true})
After setting state, React will call your components componentDidUpdate function. By comparing the current and previous state objects within this function you can signal to the parent component that your async operation has completed and your new component's state has rendered:
componentDidUpdate(_prevProps, prevState) {
if (this.state.isFetched === true && this.state.isFetched !== prevState.isFetched) {
this.props.componentHasMeaningfullyUpdated()
}
}
In your P component, you can use a counter to keep track of how many children have meaningfully updated:
function onComponentHasMeaningfullyUpdated() {
this.setState({counter: this.state.counter + 1})
}
Finally, by knowing the length of N you can know when all meaningful updates have occurred and act accordingly in your render method of P:
const childRenderingFinished = this.state.counter >= N
更多推荐
所有评论(0)