0

I have a bug in my React code where a component needs to locate an element on the page, but that element is not yet rendered.

The render method that handles calling both these components looks like this:

render() {
    const generatedId = "myComponent123"
    return (
        <ParentComponent generatedId={generatedId}>
           <ChildComponent generatedId={generatedId} />
        <ParentComponent/> 
    ) 
}

ParentComponent renders its children:

render() {
    return (
        <div id={this.props.generatedId}>
            {this.props.children}
        </div> 
    )
}

And ChildComponent needs to locate its parent component in order to set a style:

render() {
    const myParentsScrollPosition = getWindow().document.getElementById(
        this.props.generatedId
    ).scrollTop;
    return (
        <div style={{ top: `${myParentsScrollPosition}px` }}>
            ...
        </div>
    );
}

The problem I am having is that both these components get rendered async and thus when ChildComponent checks .getElementById(this.props.generatedId) that element doesn't exist. It's still rendering.

How can I make ChildComponent wait until ParentComponent has rendered and therefore will be available in the DOM?

Alternatively I am thinking of other solutions but I'm not sure. For example, could I wait for the parent to mount before rendering the children, thus assuring it will always be available in the DOM?

user1486133
  • 1,309
  • 3
  • 19
  • 37
  • I'd try to maintain the `scrollTop` value as state in the outer component (your first snippet). Then you can pass callback props to both the parent and child component, making this whole thing more imperative. – timotgl Nov 03 '20 at 14:58
  • The React way is to use Refs. Check this answer: https://stackoverflow.com/a/38093981/6705349 – Ivan Satsiuk Nov 03 '20 at 16:29

1 Answers1

0

You should not be doing this on render - it is not when elements appear on the screen (commited to DOM). You should be using componentDidMount But then you might have a problem also, cause actually componentDidMount fires first on children and only then on parent, you should try anyway, since react will commit full DOM anyway, so when children's componentDidMount will work it should mean that parent also is already in the DOM (THOUGH I DO NOT RECOMMEND THIS). I would suggest getting ref on your parent div or whatever in parent component, and from there getting it's scrollTop and passing to child directly in props.

Nikita Chayka
  • 2,057
  • 8
  • 16