Search code examples
reactjsreact-dom

getting pixel dimensions of react flexbox child?


I have an react app that uses maps a lot, and for them to render properly I need to pass in "hard" width and height in pixels. I have its container as a flexbox so its dimensions vary at render depending on device, orientation etc.

So the question is - how to find out the computed width and height of the container box at runtime so I can pass that along to the inner map?

For example:

<Column className="no-pad">
   <WalkingMap 
       isShowing={true} 
       height={this.state.mapHeight}   <-- want to pass this
       width={this.state.mapWidth}     <-- and this
   />
   <there is another sibling 'overlay' component here too>
</Column>

Can I just grab the "getElementbyId" or is that frowned upon in react world? I have tried libs like 'react-container-dimensions' but that only accepts a single child, and I will have two children because one is an overlay. The Column component is not really always a column, more a flexbox that adjusts itself. I've tried React.createRef but couldn't get it to work on the flexbox - it always comes back undefined. Any help appreciated.


Solution

  • You should try with the ref callback.

    class App extends Component {
    
        constructor(){
            super();
            this.myElement = null;
        }
    
        render(){
            return <div className="container">
                <div className="child" ref={ e => this.myElement = e }>
                </div>
            </div>;
        }
    
    }
    

    This is an extremely simplified example of two flex elements and the window resize event updating the state with the width and height of one of the DOM elements:

    https://codepen.io/rhernando/pen/caa3b5fc148590c345fd6f9b06c85437?editors=0110

    If it doesn't answer your question, please provide more concise info about your scenario and perhaps a reduced live sample.


    EDIT

    Based on your codepen sample there are two options.

    One is to use HOC and use your parent with ref forwarding:

    https://reactjs.org/docs/forwarding-refs.html

    Two, is to use this code:

    class Child extends Component {
      render() {
        return (
          <div className="child">
            <h4>Here's my dimensions</h4>
            <pre>{JSON.stringify(this.props, null, 2)}</pre>
          </div>
        );
      }
    }
    
    class Parent extends Component {
      constructor(){
        super();
        this.state = {
          width: 0, height: 0
        };
        this.container = null;
      }
    
      componentDidMount(){
        window.onresize = () => {
                this.setState({
                    width: this.container.clientWidth,
                    height: this.container.clientHeight,
                });
            };
        this.setState({
          width: this.container.clientWidth,
          height: this.container.clientHeight,
        });
      }
    
      render() {
        const { width, height } = this.state;
        return (
          <div className="parent" ref={ e => this.container = e }>
            <Child dimensions={{width, height}} />
          </div>
        );
      }
    }
    
    
    class App extends Component {
        render(){
            return (
          <div className="container">
            <Parent />
            </div>
        );
        }
    }
    

    Basically use your child component in your parent render method, unless you must pass it as a prop to the parent, and then pass the parent dimensions (those are the ones you're interested in) to the child component. This code doesn't have more side effects than the one using the child component as a prop of the parent, since the updates are the same.