React get component size

Viewed 794

My getBoundingClientRect always returns an object full with 0 values. I guess it's something related to async ? Here is the definition of the function that gets the width and x of my component.

     componentDidMount () {
         this.setState({ 
            left: Math.round(this.container.getBoundingClientRect().width),                       
           x: Math.round(this.container.getBoundingClientRect().x)                               
        });                                                                                       
  }

And here is the beginning of the render function :

render() {
        const containerStyle = {
             left : `-${Math.min(this.state.left, this.state.x) - 35}px`,                                                 
        };
        return ( !!this.state.visible && 
             <div
                 className={styles.container}
                 style={containerStyle}                                                            
                 ref={(element) => { this.container = element; }}                                  
            >

Here is the response from getBoundingClientRect

DOMRect {x: 0, y: 0, width: 0, height: 0, top: 0, …}
bottom : 0
height : 0
left : 0 
right : 0
top : 0
width : 0
x : 0
y : 0
2 Answers

Try

componentDidMount () {
  window.requestAnimationFrame(() => {
    this.setState({ 
      left: Math.round(this.container.getBoundingClientRect().width),                       
      x: Math.round(this.container.getBoundingClientRect().x)                               
    });
  }                                                                                       
}

There's some finickiness with the DOM actually being available and componentDidMount being called; using requestAnimationFrame will ensure it gets called after the paint has occurred.

You need to use a ref callback instead of an inline ref. When you use an inline ref, the first render pass the ref will be null. When you pass in a callback, it only fires once the element has loaded.

applyRef(ref) {
    this.container = ref;
}
...
<div
    className={styles.container}
    style={containerStyle}
    ref={this.applyRef}
>
Related