0

I have the following hook that I use to build responsive components throughout my App.

I looking into implementing Server Side Rendering.

useWindowWidth.js

import {useEffect, useRef, useState} from 'react';

function useWindowWidth() {
  const hasResized = useRef(false);
  const [windowSize,setWindowSize] = useState(window.innerWidth);

  useEffect(() => {

    function handleResize() {
      if (hasResized.current === true) {
        return;
      }
      hasResized.current = true;
      throtled_forceUpdate();
    }

    function throtled_forceUpdate() {
      setTimeout(()=>{
        // console.log('I will be updated!');
        // console.log(window.innerWidth);
        setWindowSize(window.innerWidth);
        hasResized.current = false;
      },250);
    }

    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return windowSize;

}

export default useWindowWidth;

App.js

import React from 'react';
import useWindowWidth from './hooks/useWindowWidth';

function App(props) {

  const windowWidth = useWindowWidth();

  return(
    windowWidth > 1200 ?
      <DesktopLayout/>
    : <MobileLayout/>
  );
}

ReactDOMServer

ReactDOMServer.renderToString(App);

What is the ReactDOMServer behavior when it encounters something like this? What is the workaround for this kind of situation?

cbdeveloper
  • 27,898
  • 37
  • 155
  • 336

1 Answers1

1

There is no way to get the window width on the server side. A workaround would be to use the useragent from the incoming request to determine which component should be rendered on the server.

const deviceType = useDeviceType();
return deviceType === 'mobile' ? <MobileLayout /> : <DesktopLayout />;

Or as the docs mention:

If you intentionally need to render something different on the server and the client, you can do a two-pass rendering. Components that render something different on the client can read a state variable like this.state.isClient, which you can set to true in componentDidMount(). This way the initial render pass will render the same content as the server, avoiding mismatches, but an additional pass will happen synchronously right after hydration. Note that this approach will make your components slower because they have to render twice, so use it with caution.

Patrick Wozniak
  • 1,492
  • 1
  • 13
  • 16
  • Thanks for you answer! I'm not a big fan of the idea of guessing the User Agent. What happens if you guess it wrong? The user will see the wrong version first? Right now I'm looking for a way to detect search engine crawlers and serve them a SSR version, and since my code needs the device width I need some way of knowing that I'm not on a broswer (I'm on a server). How would you detect that? – cbdeveloper Sep 13 '19 at 13:07
  • I'm with you.I think the best detection is to use the `window` object. If it's undefined, you are on the server. As mentioned [here](https://stackoverflow.com/questions/32216383/in-react-how-do-i-detect-if-my-component-is-rendering-from-the-client-or-the-se?#32598826). – Patrick Wozniak Sep 13 '19 at 13:23