Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change props depending on breakpoint with SSR support

I'm using material-ui@v5, ie. the alpha branch.

Currently, I have a custom Timeline component which does this:

const CustomTimeline = () => {
  const mdDown = useMediaQuery(theme => theme.breakpoints.down("md"));

  return (
    <Timeline position={mdDown ? "right" : "alternate"}>
      {/* some children */}
    </Timeline>
  );
};

It works mostly as intended, but mobile users may experience layout shift because useMediaQuery is implemented using JS and is client-side only. I would like to seek a CSS implementation equivalence to the above code to work with SSR.

I have thought of the following:

const CustomTimeline = () => {

  return (
    <Fragment>
      <Timeline sx={{ display: { xs: "block", md: "none" } }} position="right">
        {/* some children */}
      </Timeline>
      <Timeline sx={{ display: { xs: "none", md: "block" } }} position="alternate">
        {/* some children */}
      </Timeline>
    </Fragment>
  );
};

This will work since the sx prop is converted into emotion styling and embedded in the HTML file, but this will increase the DOM size. Is there a better way to achieve that?

like image 273
Matthew Kwong Avatar asked May 13 '21 07:05

Matthew Kwong


People also ask

How to change the value of a prop in react responsive CSS?

Responsive CSS in React has a glaring weakness: it doesn't allow you to responsively change the values of props. Instead of writing CSS wrapped in media queries, responsive props is a method where you specify the value of the prop for predefined breakpoints and logic exists somewhere that chooses the value associated with the active breakpoint.

How to highlight text when prop is changed by parent component?

The guide will start with a very simple label component that will have a prop called text and display it inside a span, then extend this component to highlight the text when the prop is changed by the parent component.

How does the breakpoint service work?

This service works in conjunction with grids and other responsive helper classes (e.g. display ). The breakpoint service is a programmatic way of accessing viewport information within components. It exposes a number of properties on the $vuetify object that can be used to control aspects of your application based upon the viewport size.

What are responsive props and how do I use them?

Instead of writing CSS wrapped in media queries, responsive props is a method where you specify the value of the prop for predefined breakpoints and logic exists somewhere that chooses the value associated with the active breakpoint. Why would you want to do that? Let's say you have different button sizes: large, medium, small.


1 Answers

I have experienced the same problem before and I was using Next.js to handle SSR. But it does not matter.

Please first install this package and import it on your root, like App.js

import mediaQuery from 'css-mediaquery';

Then, create this function to pass ThemeProvider of material-ui

  const ssrMatchMedia = useCallback(
        (query) => {
            const deviceType = parser(userAgent).device.type || 'desktop';
            return {
                matches: mediaQuery.match(query, {
                    width: deviceType === 'mobile' ? '0px' : '1024px'
                })
            };
        },
        [userAgent]
    );

You should pass the userAgent!

Then pass ssrMatchMedia to MuiUseMediaQuery

<ThemeProvider
                theme={{
                    ...theme,
                    props: {
                        ...theme.props,
                        MuiUseMediaQuery: {
                            ssrMatchMedia
                        }
                    }
                }}>

This should work. I am not using material-UI v5. Using the old one. MuiUseMediaQuery name might be changed but this approach avoid shifting for me. Let me know if it works.

like image 79
oakar Avatar answered Oct 13 '22 22:10

oakar