Handle Browser Window Resize in React

FrontEnd Reading Time: 2 min.

  • views3924
  • 6comments
Share

One of the most frustrating things which each frontend developer faces, is the challenge of scaling graphs library. It very often happens, especially with an older library, that it is not responsive. It just adjusts the size when it is mounted to the DOM and doesn’t scale dynamically when a browser window is resizing.

How can we solve this issue?

Of course the first thing we can do, is to try to replace it with another one. However, in practice, this solution is rarely possible, especially when we are working with legacy software where a mass of other components are already using it. In that case, reworking the code of all components doesn’t make any sense. So what then? Well,  fortunately, if you know React you don’t have to worry. In the React world everything is simple, and this case is no different. What we have to do is just force re-render to our component each time the browser windows change size. Thanks to that we will be able to recalculate a new dimension for our object and bring it back with a new, adjusted size.

How to do this? Check code below.


import React, { Component } from 'react';
import LineChart from 'chart-graphs';

export default class Chart extends Component {

  constructor() {
    super();
    this.state = {
      width:  800,
      height: 182
    }
  }

  /**
   * Calculate & Update state of new dimensions
   */
  updateDimensions() {
    if(window.innerWidth < 500) {
      this.setState({ width: 450, height: 102 });
    } else {
      let update_width  = window.innerWidth-100;
      let update_height = Math.round(update_width/4.4);
      this.setState({ width: update_width, height: update_height });
    }
  }

  /**
   * Add event listener
   */
  componentDidMount() {
    this.updateDimensions();
    window.addEventListener("resize", this.updateDimensions.bind(this));
  }

  /**
   * Remove event listener
   */
  componentWillUnmount() {
    window.removeEventListener("resize", this.updateDimensions.bind(this));
  }

  render() {
    return(
      <div id="lineChart"> 
         <LineChart width={this.state.width} height={this.state.height} /> 
      </div>
    );
  }
}
Tagged with:

Tags: ,

  • Mdversion01

    I’m trying to get the width of the browser on resize, and if it is below 767px, then I want it to swap out classes. I did it with jquery but now I’m trying to do it with React. I’m new to React so help would be greatly appreciated.

    jQuery version:

    jQuery(document).ready(function($){

    //get the window width
    var winWidth = $(window).width();

    //set the maxWidth
    var maxWidth = 767;

    //if the window width is less than the maxWidth pixels on document loading
    if(winWidth < maxWidth){//begin if then

    //add the class hidden to .jobFilter
    $(".collapse").removeClass("in");
    //$(".title").removeClass("in");
    $(".title").addClass("collapsed");

    }//end if then

    $(window).resize(function(){//begin resize event

    //get the window width
    var winWidth = $(window).width();

    //set the maxWidth
    var maxWidth = 767;

    //if the window width is less than maxWidth pixels
    if(winWidth < maxWidth){//begin if then

    //add the class hidden to .jobFilter
    $(".collapse").removeClass("in");
    $(".title").addClass("collapsed");
    }
    else{

    //remove the class hidden
    $(".collapse").addClass("in");
    $(".title").removeClass("collapsed");

    }//end if then else
    });//end window resize event
    });//end document ready function

    My Reactjs version so far:

    updateDimensions() {
    var winWidth = $(window).width();
    var maxWidth = 767;
    //this.setState({facetTitleClass:''});
    //this.setState({facetContentCLass: 'in'});
    if(winWidth < maxWidth){
    this.setState({facetTitleClass:'collapsed'});
    this.setState({facetContentCLass: ''});
    } else {
    this.setState({facetTitleClass:''});
    this.setState({facetContentCLass: 'in'});
    }
    }
    componentWillMount() {
    this.updateDimensions();
    }
    componentDidMount() {
    this.updateDimensions();
    window.addEventListener("resize", this.updateDimensions);
    }
    componentWillUnmount() {
    window.removeEventListener("resize", this.updateDimensions);
    }

    • Mdversion01

      Nevermind. I figured it out from re-reading your post. My answer was:

      constructor(props) {
      super(props);
      this.state = {
      facetTitleClass:”,
      facetContentClass: ‘in’
      };
      }

      updateDimensions() {
      var winWidth = $(window).width();
      var maxWidth = 767;
      if(winWidth < maxWidth){
      this.setState({facetTitleClass:'collapsed'});
      this.setState({facetContentClass: ''});
      } else {
      this.setState({facetTitleClass:''});
      this.setState({facetContentClass: 'in'});
      }
      }
      componentWillMount() {
      this.updateDimensions();
      }
      componentDidMount() {
      this.updateDimensions();
      window.addEventListener("resize", this.updateDimensions.bind(this));
      }
      componentWillUnmount() {
      window.removeEventListener("resize", this.updateDimensions.bind(this));
      }

  • Chris Noreikis

    One thing to be careful about with the .bind function is that it creates a new instance of the target function.

    The addEventListener, removeEventListener functions above introduce a subtle bug when this component is unmounted. Since .bind returns a brand new function, calling

    window.removeEventListener(“resize”, this.updateDimensions.bind(this));

    Won’t actually find and remove the original listener, since this.updateDimensions.bind(this) is a new, unbound function.

    The common React pattern for solving this problem is to bind functions to the component instance in the constructor, i.e:

    constructor() {
    super();
    this.updateDimensions = this.updateDimensions.bind(this);
    }

    Then, calls to:

    window.addEventListener(“resize”, this.updateDimensions);
    window.removeEventListener(“resize”, this.updateDimensions);

    Will work as expected.

    • Paul Fabbroni

      This is bang on. I was just using this code and experiencing a console error which was fixed thanks to your comment. Thank-you

    • FYI <pre><code> will format code blocks on disqus


      const soLike = function yourCode() {
      const becomes = window.readable; // or something
      }