Rob Rob - 3 months ago 30
React JSX Question

Resize D3 Chart to Parent in React

I was working through the tutorial from: http://ahmadchatha.com/writings/article1.html

And it sets you up with a React Component like this:

class SimplePie extends React.Component {
render() {
return (
<div className="col-xs-4 chart"
style={{background: this.props.data[1]}} >
{this.props.title}
<D3Chart
width={200}
height={200}>
<DataSeries
data={this.props.data[0]}
colors={colors}
width={200} height={200} />
</D3Chart>
</div>
)
}
}


But I want to change this so the D3Chart will resize based on the size of parent, and listen for resize events. Is there any easy way to do this in React?

I am struggling with event listeners for resize events on a particular div.

Answer

Measuring sizes of elements with React is not as straight forward as you might think, the main reason for this is that React doesn't really care about sizes, you must read them from the DOM, after they are drawn.

For your case here we can utilize the componentDidMount, componentDidUpdate lifecycle functions and a vanilla JavaScript resize event on the window element, like so:

class SimplePie extends React.Component {
  constructor (props, context) {
    super(props, context);
    this.state = {
           width: 200,
           height: 200
        };
    this.measure = this.measure.bind(this);
  }
  componentWillMount () {
    window.addEventListener('resize', this.measure, false);
  }
  componentWillUnmount () {
    window.removeEventListener('resize', this.measure, false);
  }
  measure () {
    let rect = this.container.getBoundingClientRect();
    if(this.state.width !== rect.width || this.state.height !== rect.height){
       this.setState({
              width: rect.width, 
              height: rect.height
           });
    }
  }
  componentDidMount (){
     this.measure();
  }
  componentDidUpdate (){
     this.measure();
  }
  render() {
    return (
      <div ref={(container)=>{this.container = container}} style={{width: "100%", height: 300}} className="col-xs-4 chart"
        style={{background: this.props.data[1]}} >
        {this.props.title}
        <D3Chart
          width={this.state.width}
          height={this.state.height}>
          <DataSeries
            data={this.props.data[0]}
            colors={colors}
            width={this.state.width} height={this.state.height} />
        </D3Chart>
      </div>
    )
  }
}

Edit: The container must have a fixed width and height, if you want to use percentage based height you must set the height of the parent of this component.