Search code examples
javascriptreactjsdom-eventsevent-listenerwindow-resize

Higher Order Component (HOC) and window resize listener


I have the following HOC and I thought about creating 3 states where these would be my breakpoints

  • mobile
  • tablet
  • desktop

But I'm wondering how I could set these states to true when a breakpoint is reached example:

  • mobile: less than 767
  • tablet: between 768 and 991
  • desktop: between 992 and 1919
  • large screens: 1919 and 2520

and then when one of these breakpoins was reached the state would change to true

Also how I could do to pass only one state (whichever is true) at the moment in my HOC?

Can I improve this logic?

import React from "react";

const withWindowResize = Component => {
  class WrappedComponent extends React.Component {
    constructor(props) {
      super(props);

      this.state = {
        height: 0,
        width: 0,
        mobile: false,
        desktop: false,
        tablet: false
      };
      window.addEventListener("resize", this.resizeUpdate);
    }

    componentDidMount() {
      this.update();
    }

    resizeUpdate = () => {
      this.setState({
        height: window.innerHeight,
        width: window.innerWidth
      });
    };

    render() {
      return <Component />;
    }
  }
  return WrappedComponent;
};

export default withWindowResize;

Solution

  • There are plenty of ways to do it, but following your approach, you could do something like the following, where you just have a size variable on your state changing based on the specs you provided above.

    In that way, you just have to pass this.state.size to your component.

    import React from "react";
    
    const withWindowResize = Component => {
      class WrappedComponent extends React.PureComponent {
        constructor(props) {
          super(props);
    
          this.state = {
            size: this.findSize()
          };
        }
    
        componentDidMount() {
          window.addEventListener("resize", this.resizeUpdate.bind(this)); // initialize your listener
        }
    
        componentWillUnmount() { // remove event listener on component unmount
          window.removeEventListener("resize", this.resizeUpdate.bind(this));
        }
    
        findSize() {
          return window.innerWidth > 1919
              ? "large"
              : window.innerWidth > 992
              ? "desktop"
              : window.innerWidth > 768
              ? "tablet"
              : "mobile"; // find currentSize
        }
    
        resizeUpdate() {
          const currentSize = this.findSize();
    
          this.setState({
            size: currentSize
          });
        }
    
        render() {
          return <Component size={this.state.size} />;
        }
      }
    
      return WrappedComponent;
    };
    
    export default withWindowResize;
    

    Notice I'm using React.PureComponent as we don't want to change our state and re-render our Component on every window resize.

    This will be the same as using React.Component and checking right before the use of this.setState, if our currentSize is different from the one we have on state, before updating it.

    if (currentSize !== this.state.size) {
      this.setState({
        size: currentSize
      });
    }