Semantic-ui-react: Responsive: SSR is broken

Created on 1 Jan 2019  路  8Comments  路  Source: Semantic-Org/Semantic-UI-React

Stack:
Latest versions of Next.js, React, Semanic UI React.

Issue:
When I attempt to render the the example layout from here using Next.js, I get a warning that says Expected server HTML to contain a matching <div> in [<div>.]

I believe it's related to this issue https://github.com/Semantic-Org/Semantic-UI-React/issues/3110 which has something to do with the server not getting the browser size.

However, none of the solutions in that link worked for me. One requirement I have is that SSR cannot be turned off.

Here's the code I'm using: https://github.com/jlei523/semantic-ui-next

Minor note: I believe https://react.semantic-ui.com/layouts/homepage/ is also affected by this issue. Go to the URL and then refresh the page and you should see the styles get messed up. If you shrink the browser window and then shrink it back, it displays the elements correctly again.

Has anyone solved this problem already without turning SSR off? Also, does anyone have an example of how to do display mobile specific elements using SUIR without turning off SSR?

question

Most helpful comment

Solution 1: use react-no-ssr

It's simple, will omit all warnings.

+import NoSSR from 'react-no-ssr'

//

-<div>
+<NoSSR>
  <DesktopContainer>{children}</DesktopContainer>
  <MobileContainer>{children}</MobileContainer>
-</NoSSR>
+</div>

HalfSolution 2: use getWidth() prop

const isBrowser = () => typeof window !== 'undefined'
const getWidth = () => {
  if (isBrowser()) return window.innerWidth
  return 1000
}
-<Responsive>
+<Responsive getWidth={getWidth}>

Still will cause a warning on mobile devices 馃悧

Solution 3: use mobile-detect

The best solution that I know, everything works like a charm 馃憤

+import MobileDetect from 'mobile-detect'

+const getWidthFactory = (isMobileFromSSR) => () => {
+  const isSSR = typeof window === 'undefined';
+  const ssrValue = isMobileFromSSR ? 767 : 768
+
+  return isSSR ? ssrValue : window.innerWidth
+}

//

-const HomepageLayout = () => (
+const HomepageLayout = ({ getWidth }) => (

//

+HomepageLayout.getInitialProps = async ({ req }) => {
+  const result = new MobileDetect(req.headers['user-agent'])
+  const isMobile = !!result.mobile()
+
+  return { getWidth: getWidthFactory(isMobile) }
+}

//

-const ResponsiveContainer = ({ children }) => (
-const ResponsiveContainer = ({ children, getWidth }) => (
  <div>
-    <DesktopContainer>{children}</DesktopContainer>
-    <MobileContainer>{children}</MobileContainer>
+    <DesktopContainer getWidth={getWidth}>{children}</DesktopContainer>
+    <MobileContainer getWidth={getWidth}>{children}</MobileContainer>
  </div>
);

Live example on Codesandbox: https://codesandbox.io/s/ly3zpw7yzm

All 8 comments

Solution 1: use react-no-ssr

It's simple, will omit all warnings.

+import NoSSR from 'react-no-ssr'

//

-<div>
+<NoSSR>
  <DesktopContainer>{children}</DesktopContainer>
  <MobileContainer>{children}</MobileContainer>
-</NoSSR>
+</div>

HalfSolution 2: use getWidth() prop

const isBrowser = () => typeof window !== 'undefined'
const getWidth = () => {
  if (isBrowser()) return window.innerWidth
  return 1000
}
-<Responsive>
+<Responsive getWidth={getWidth}>

Still will cause a warning on mobile devices 馃悧

Solution 3: use mobile-detect

The best solution that I know, everything works like a charm 馃憤

+import MobileDetect from 'mobile-detect'

+const getWidthFactory = (isMobileFromSSR) => () => {
+  const isSSR = typeof window === 'undefined';
+  const ssrValue = isMobileFromSSR ? 767 : 768
+
+  return isSSR ? ssrValue : window.innerWidth
+}

//

-const HomepageLayout = () => (
+const HomepageLayout = ({ getWidth }) => (

//

+HomepageLayout.getInitialProps = async ({ req }) => {
+  const result = new MobileDetect(req.headers['user-agent'])
+  const isMobile = !!result.mobile()
+
+  return { getWidth: getWidthFactory(isMobile) }
+}

//

-const ResponsiveContainer = ({ children }) => (
-const ResponsiveContainer = ({ children, getWidth }) => (
  <div>
-    <DesktopContainer>{children}</DesktopContainer>
-    <MobileContainer>{children}</MobileContainer>
+    <DesktopContainer getWidth={getWidth}>{children}</DesktopContainer>
+    <MobileContainer getWidth={getWidth}>{children}</MobileContainer>
  </div>
);

Live example on Codesandbox: https://codesandbox.io/s/ly3zpw7yzm

In #3373 I added notes about SSR, the solution above is now in our docs 猸愶笍

I'm having the same problem.

I'm trying to implement the example at https://github.com/Semantic-Org/Semantic-UI-React/blob/master/docs/src/layouts/HomepageLayout.js

it works with desktop size both client and SSR, but if you SSR on mobile size I'm getting

Warning: Expected server HTML to contain a matching <a> in <div>.

Please take a look at codesandbox example, it contains the completely working solution.

thanks layershifter, I have tested your solution and it works on mobile and desktop, but not on Tablet.

when the user agent is iPad I get
index.js:2178 Warning: Text content did not match. Server: "MobileContainer" Client: "DesktopContainer"

Feel free to add necessary changes to the code, it's an example.

Hope this bug should be fixed soon. Not a workaround.

https://github.com/Semantic-Org/Semantic-UI-React/issues/4002#issuecomment-665000116

Responsive will be deprecated and removed. I will provide an upgrade guide.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

keeslinp picture keeslinp  路  3Comments

mattmacpherson picture mattmacpherson  路  3Comments

SajagTiwari picture SajagTiwari  路  3Comments

eXtreme picture eXtreme  路  3Comments

ryanpcmcquen picture ryanpcmcquen  路  3Comments