skip to Main Content

On the website I create in Gatsby I would like to check the size of the DOM window.innerWidth before it will be first rendered. I would like to use a conditional check of innerWidth to decide how the website should be rendered: as desktop or mobile version.
A simple fix for that would be to check the width of the window before creating react component and use the true/false value further in the code. It works in development version but…
The case is that in production version when I do gatsby build, I get an error in console:

failed Building static HTML for pages - 2.872s

 ERROR #95312 

"window" is not available during server-side rendering.

See our docs page for more info on this error: https://gatsby.dev/debug-html

> 30 |     const sizeOfWindow = window.innerWidth;

I tried already to use componentWillMount which works fine but it is deprecated and marked as unsafe.
If I check the window.innerWidth in componentDidMount doesn’t render properly.

My code:

interface IndexPageState {
  isDesktop: boolean;
  windowWidth: number;
}

class IndexPage extends React.Component<any, IndexPageState> {
  constructor(props: any) {
    super(props);

    this.state = {
      windowWidth: 0,
      isDesktop: true,
    };
  }

  componentWillMount(): void {
    this.onResize();
  }

  onResize = () => {
    if (!(this.state.windowWidth >= 769)) {
      this.setState({ isDesktop: false });
    } else {
      this.setState({ isDesktop: true });
    }
  };

  componentDidMount = () => {
    this.setState({ windowWidth: window.innerWidth });
    if (!(this.state.windowWidth >= 769)) {
      this.setState({ isDesktop: false });
    } else {
      this.setState({ isDesktop: true });
    }
    window.addEventListener('resize', this.onResize);
  };

  componentWillUnmount = () => {
    window.removeEventListener('resize', this.onResize);
  };

  render() {
    const { isDesktop, windowWidth } = this.state;

    return (
      <>
        <SEO title="Home" />
        <div className={styles.App}>

3

Answers


  1. You can wrap getting the window width in the callback, so add function getWindowWidth where you will return the actual window width.

    Login or Signup to reply.
  2. Try to execute window.innerWidth after checking the window is defined first in this way.

    componentDidMount() {
        if (typeof window !== 'undefined') {
            window.addEventListener('resize', this.onResize)
        }
    }
    componentWillUnmount() {
        if (typeof window !== 'undefined') {
            window.removeEventListener('resize', this.onResize)
        }
    }
    
    Login or Signup to reply.
  3. With Gatsby, you must check for the availability of the browser global variables like document or window, since at the time your code is compiling and asking for those variables, they may not be declared/available yet.

    From the Gatsby documentation:

    Some of your code references “browser globals” like window or
    document. If this is your problem you should see an error above like
    “window is not defined”. To fix this, find the offending code and
    either a) check before calling the code if window is defined so the
    code doesn’t run while Gatsby is building (see code sample below) or
    b) if the code is in the render function of a React.js component, move
    that code into a componentDidMount lifecycle or into a useEffect hook,
    which ensures the code doesn’t run unless it’s in the browser

    So, every time you check for the window, you must add:

        if(typeof window !== undefined){
         //your stuff
        }
    

    Applied to your code:

      componentDidMount = () => {
        if(typeof window !== undefined){
          this.setState({ windowWidth: window.innerWidth });
          if (!(this.state.windowWidth >= 769)) {
            this.setState({ isDesktop: false });
          } else {
            this.setState({ isDesktop: true });
          }
          window.addEventListener('resize', this.onResize);
        }
      };
    
    
      componentWillUnmount = () => {
        if(typeof window !== undefined){
          window.removeEventListener('resize', this.onResize);
        }
    
       onResize = () => {
        if(typeof window !== undefined){ 
           if (!(this.state.windowWidth >= 769)) {
             this.setState({ isDesktop: false });
           } else {
           this.setState({ isDesktop: true });
           }
         }
       };
    };
    

    Of course, the code above should be refactored to avoid the repetition of the condition, by adding the window condition before the event is triggered for example.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search