Adjust properties based on screen size with server-side rendering compatibility

I'm currently using the alpha branch of material-ui@v5.

At the moment, I have developed a custom Timeline component that functions like this:

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

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

Although it works mostly as intended, mobile users might encounter layout shifts due to the fact that useMediaQuery relies on JavaScript and is only executed client-side. I am searching for a CSS-based solution that can be used with Server-Side Rendering (SSR).

One potential approach I've considered is:

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 solution should work because the sx prop gets converted into emotion styling and gets included in the HTML file. However, this method will increase the size of the DOM. Are there any better alternatives to achieve the same result?

Answer №1

I encountered a similar issue in the past while utilizing Next.js for SSR, however, the solution is not dependent on that.

Start by installing this package and importing it into your root file, such as App.js

import mediaQuery from 'css-mediaquery';

Next, create a 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]
);

Make sure to provide the userAgent!

Then, include ssrMatchMedia in MuiUseMediaQuery

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

This approach should function correctly. I am utilizing an older version of material-UI instead of v5. The name MuiUseMediaQuery might be different, but this method has been effective for me thus far. Feel free to inform me if you encounter any issues.

Answer №2

In order to prevent the initial rendering before useMediaQuery is launched, it is recommended to follow the advice from the Reactjs documentation. One option is to move that logic to useEffect if it is not essential for the first render. Another approach is to delay displaying that component until after the client renders, especially if the HTML appears broken until useLayoutEffect runs.

To avoid including a component that relies on layout effects in the server-rendered HTML, you can conditionally render it using showChild && and defer its display with useEffect(() => { setShowChild(true); }, []). By doing this, the UI will not appear broken before hydration.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Error when compiling TypeScript: The callback function provided in Array.map is not callable

This is a Node.js API that has been written in Typescript. app.post('/photos/upload', upload.array('photos', 12), async (req, res) => { var response = { } var list = [] try { const col = await loadCollection(COLLECTION_NAM ...

Store the beginning and ending times in a MySQL database using Sequelize and Node.js

I am currently developing a project management application where I need to keep track of the start and stop time for user work. To achieve this, I have implemented two buttons in the UI - START and STOP. When a user clicks the START button, the following ...

Is it possible to use the same HTML select/dropdown menu for multiple rows in a table?

I am working with an HTML table that usually has between 10-30 rows, each containing a column for "item name". The drop down menu consists of about 75 products to choose from. In order to reduce the page size, I want to use a single drop down list for all ...

Leverage the power of Next.js to dynamically render a specific section of an HTML webpage

I want to incorporate Next.js into a specific section of my website, while the rest of the site is built using different frameworks that are not even based on React. I aim to use Next.js within a <div id="nextjs_div">...</div> element ...

Issues with Three.js raycaster intersectObjects

I am currently working on a 3D scatter plot where spheres are used to represent the points, and I am attempting to show information from the points when they are clicked. After researching various answers on this platform, I believe I am moving in the righ ...

Storing Byte Array in a File using JavaScript

I am working on a Java REST webservice that returns documents as byte array. I am trying to write JavaScript code that will retrieve the response from the webservice and save it to a file for downloading as a PDF. However, when testing my sample code, the ...

What is the best way to retrieve a response from a PHP file as an array through Ajax?

Seeking assistance in retrieving a complete address by entering the postal code in an HTML form textbox and clicking a button. The setup involves two files - one containing the ajax function and the other housing the PHP code. Uncertainty looms over whethe ...

Looking to utilize flash player within React Electron Web View

I'm currently working on a React-Electron project and have integrated the react-electron-web-view package, which utilizes browserify for displaying websites. However, I've encountered an issue with certain websites that still rely on Flash Player ...

When attempting to click on my subtopics using jQuery, they do not appear as expected

$(document).ready(function () { $("#subTopics").hide(); $("#mainTopics").click(function () { $("#subTopics").show("slow"); }); }); body { margin: 0; } li, a{ text-decoration: none; list-style-type: none; text-d ...

Why will the experimental activation of React concurrent features in Nextjs 12 disable API routes?

I just upgraded to Next.js version 12 and set up some API routes (e.g. "/api/products"). These routes were functioning properly, but when I enabled concurrentFeatures: true in my next.config.ts, the API routes stopped working. The console display ...

When the react button is clicked, there is no feedback or message displayed

When I tried to click the button to test if it was clicked or not, I noticed that there was no response when I clicked it. Am I missing something here? import React, { Component } from 'react'; import './App.css'; class App extends ...

Failed to retrieve information using a custom header in the HTTP request

My AngularJS code works well without the header option. $http.get(env.apiURL()+'/banks', { headers: { 'Authorization': 'Bearer '+localStorageService.get('access_token') } }) Here is the request: OP ...

The Node.js application gracefully exited with code 0 with Forever

Running a Node.js Express app on CentOs 6.5 using the root account: root@vps [/home/test/node]# npm start app.js > <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="aedacbdddaee9e809e809f">[email protected]</a> s ...

Is the original image source revealed when clicked?

I've implemented an expand and collapse feature using jQuery/JavaScript. Clicking on the DIV causes the image inside to change state. However, clicking on the same DIV again doesn't return the image to its original state; it remains stuck in the ...

When I type text into the form field, JavaScript causes a disruption in the form

I'm attempting to implement a dual-stage user onboarding procedure. Initially, users will input the industry they belong to and then provide a description. Upon clicking submit, my intention is to conceal that portion of the form and reveal the "Creat ...

Demonstrating various elements within an application using Vue3

I created two components and attempted to display them in a Vue 3 application. Here is my HTML code: <div id="app"> <image_preview> URL: [[image]] </image_preview> <file_uploader> Counter:[[coun ...

Struggling with defining the default value for a JavaScript array

One interesting feature on my website is a changing h1 heading that updates when the user clicks a button. However, I encountered an issue where, upon initial page load, the h1 appears empty and only populates with text after the button is clicked. I am ...

Steps for assigning an id to an element using Selenium

When using Selenium, you have the ability to access the underlying DOM of the browser being manipulated through IWebElement instances. For example: IWebElement domWrapper = driver.FindElement(By.Name("q")); But what if you have the "domWrapper" instance ...

Following a POST request, the redirection functionality in Next.js seems to be malfunctioning

I am facing an issue with redirecting the user after submitting a form. I have a button that triggers a post request to my API route, which then inserts a row in the database. The goal is to redirect the user to / once everything is done. However, the retu ...

What steps should I take to troubleshoot and resolve the connection issue that arises while trying to execute npm install

Following the guidelines from: https://www.electronjs.org/docs/tutorial/first-app I executed commands like mkdir, cd, and npm init. They all ran successfully, generating a file named package.json. Subsequently, I entered npm install --save-dev electron w ...