R01010010
R01010010

Reputation: 5958

componentDidMount called before real DOM is available

I'm very new to React. I need to get the height of an element, so I'm trying to get it at componentDidMount method. I understood that this method was called after rendering the component, which is at the end to write the real DOM I assume. However, componentDidMount is being called before the final DOM is available. How come?

componentDidMount() {
  const el = window.document.getElementById('comments'); // el is null
  console.log(el);  
}

resize() {
  const el = window.document.getElementById('comments'); // el is null
  console.log(el);
}

render() {
  const { name } = this.props;
  const Comments = this.props.comments.filter(comment => comment.body !== null && comment.body !== '').map(comment => <Comment key={comment.id} comment={comment} />);
  return (
    <div ref={this.resize}>
      <div>
        <div id="comments">
          { Comments }
        </div>
      </div>
    </div>
  );
}

Upvotes: 1

Views: 2567

Answers (2)

Rosmarine Popcorn
Rosmarine Popcorn

Reputation: 10967

On React you shouldn't rely on DOM that is returned by render method. The component and the render part are 2 different processes in React so the approach from outside in doesn't work in React. What you can do is, save comments as a ref :

 componentDidMount() {
      var erd = elementResizeDetectorMaker();
      erd.listenTo(this.refs.comments, resize);
    }

    resize(element) {
       //do-some-thing
    }

    render() {
      const { name } = this.props;
      const Comments = this.props.comments.filter(comment => comment.body !== null && comment.body !== '').map(comment => <Comment key={comment.id} comment={comment} />);
      return (
        <div>
          <div>
            <div ref={comments => { this.comments = comments; }}>
              { Comments }
            </div>
          </div>
        </div>
      );

}

PS : In a similar situation I used this amazing library : https://github.com/wnr/element-resize-detector

Upvotes: 2

Rui Costa
Rui Costa

Reputation: 800

Your selector const el = window.document.getElementById('comments'); (this is anti pattern) is null because your select Node don't exist on componentDidiMount render lifecycle.

You need select your node's inner React pattern (or shadow DOM).

Change your code for this code block, replace javascript selector 'getElementBy' for refs of React. Check documentation https://facebook.github.io/react/docs/refs-and-the-dom.html

componentDidMount() {
  let el = this.refs['comments']
  console.log(el.clientHeight)
  this.resize()
}

resize() {
  let el = this.refs['comments']
  console.log(el.clientHeight)
}

render() {
  const { name } = this.props;
  const Comments = this.props.comments.filter(comment => comment.body !== null && comment.body !== '').map(comment => <Comment key={comment.id} comment={comment} />);
  return (
    <div ref='comments'>
      <div>
        <div id="comments">
          { Comments }
        </div>
      </div>
    </div>
  );
}

Upvotes: 0

Related Questions