How to do SSR for responsive apps without knowing the device's screen size upfront?

Viewed 1346

I want to SSR my app for my users.

But my app code uses a useEffect to detect what is the size of the user's screen width, and only then the App is rendered.

Something like:

App.js

  // THE LAYOUT INITIAL STATE IS NULL

  useEffect(() => {
    // CHECK FOR window.innerWidth AND DECIDE LAYOUT
    // UPDATE LAYOUT STATE
  });

  return(
    layout && <AppComponents>   // IF THERE IS NO LAYOUT, NOTHING IS RENDERED
  );

Component.js

 // I SERVE THE LAYOUT THROUGH CONTEXT AND I ACCESS IT INSIDE OF THE COMPONENTS

 const layout = useLayout();

 return(
   layout === "MOBILE" ? ComponentMobile : ComponentDesktop
 );

QUESTION

I cannot rely on a code inside of a useEffect to render stuff on the server. So, somehow I need to "decide" which layout to use for the first and only render on the server.

So my options, at least the ones I've though of so far, are:

OPTION #1

Try to guess the user's device screen size, and render something that might not be optimal for their screen size.

Because right now, the CSS styles that I'm rendering depend on the user's screen size.

OPTION #2

Move entirely to media queries to handle responsiveness, so the CSS will always be the same and it will adapt automatically to whatever size of screen is being used.

So far I haven't been using media queries at all. All my layout decisions are made during the render, and all the component render the styles based on the layout that was decided from App.js state.


What is the best way of handling this? Is there a best practice for this?

NOTE:

I am using styled-components, so this is basically what I do:

This is a crude example, but that's the idea.


// THIS IS MUCH EASIER TO WRITE THAN A BUNCH OF MEDIA QUERIES (IMO)

const Styled_DIV = styled.div`
  font-size: ${props => 
    props.layout === "MOBILE" ? "16px" 
    : props.layout === "TABLET" ? "18px" 
    : "20px"
  };
`;
1 Answers

Great, you're already using styled-components. Adding media queries is now trivial and actually more straightforward (IMO) than your suggested method.

In general, configuring layout with CSS performs better than with JS. And with SSR, like you said, the server can't determine the screen size yet with JS and useEffect.

If you're mobile first, you can write the above logic with media queries like this:

const Styled_DIV = styled.div`
  font-size: 16px;

  @media (min-width: 768px) {
    font-size: 18px;
  }

  @media (min-width: 1024px) {
    font-size: 20px;
  }
`

I wrote a helper object export so I don't have to remember the pixel sizes or even the syntax for media queries:

export const size = {
  tablet: 768,
  desktop: 1024,
}

export const device = {
  tablet: `@media (min-width: ${size.tablet}px)`,
  desktop: `@media (min-width: ${size.desktop}px)`,
}

So now I just have to write:

const Styled_DIV = styled.div`
  font-size: 16px;

  ${device.tablet} {
    font-size: 18px;
  }

  ${device.desktop} {
    font-size: 20px;
  }
`

Since device is an exported object, my VSCode editor automatically helps me import it when I start typing.

Related