在 Next.js SSR 中检测设备的正确方法是什么?

ton*_*on1 6 reactjs server-side-rendering next.js

我有<MobileLayout /><DesktopLayout />。我用于Next.js服务器端渲染。我注意到有许多著名的 ui 库都有移动检测组件,例如<Respnosive />Semantic-UI-React 中的组件。但所有这些都是客户端方法,无法正常工作SSR

我阅读了一些文档,结论是我应该检查user-agent服务器端req.headers。在 Next.js 中,检测设备并有条件渲染MobileLayout/之一的正确方法是什么DesktopLayout

我尝试过的

_app.js

import isMobile from 'ismobilejs'

...

function Homepage({ Component, pageProps, mobile }){
  return (
    mobile ? 
      <MobileLayout><Component {...pageProps} /></MobileLayout> : 
      <DesktopLayout><Component {...pageProps} /></DesktopLayout>
  )
}

HomePage.getInitialProps = async (appContext) => {
  const userAgent = appContext.ctx.req.headers['user-agent']
  const mobile = isMobile(userAgent).any
  const appProps = await App.getInitialProps(appContext)
  return { ...appProps, mobile }
}
Run Code Online (Sandbox Code Playgroud)

但问题是 getIntialProps 在_app.js每次页面加载时执行。通过与客户端移动页面,它appContext.ctxundefined省略错误。我认为这个方法可能会阻止一些 nextjs 内置优化。

错误页面中的错误getInitialProps:TypeError:无法读取未定义的属性“标题”

那么在 Next.js 中检查设备的正确方法是什么?

jda*_*daz 2

如果您想使用 检测用户的设备userAgent,最好的选择是这个答案

IndexPage.getInitialProps = ({ req }) => {
  let userAgent;
  if (req) { // if you are on the server and you get a 'req' property from your context
    userAgent = req.headers['user-agent'] // get the user-agent from the headers
  } else {
    userAgent = navigator.userAgent // if you are on the client you can access the navigator from the window object
  }
}
Run Code Online (Sandbox Code Playgroud)

(请注意,如果您有 Next 9.3 或更高版本,您实际上应该使用 getServerSidePropsor getStaticProps,但有时该功能没有替代品getInitialProps。)

然而,Mozilla 的人员建议

值得重申的是:使用用户代理嗅探很少是个好主意。您几乎总能找到更好、更广泛兼容的方法来解决您的问题!

您正在导入的isMobile 包的制造商甚至警告:

您可能不需要这个库。在大多数情况下,响应式设计 解决了控制如何在不同屏幕尺寸上渲染事物的问题。

因此,看看是否可以使用CSS3 媒体查询来有条件地渲染某些元素或更改其大小等,而不是使用完全独立的移动和桌面布局组件。但您可能会遇到一种极端情况,无法使任何替代选项发挥作用。

如果您要保留当前设置并在其他页面上使用两种布局,您可以考虑将它们组合到一个父<Layout>组件中,该父组件有条件地呈现其中一个或另一个,这样您就不必将该逻辑复制到每个页面中:

export const Layout = (props) => {
      return (
          props.mobile ? 
          <MobileLayout>{props.children}</MobileLayout> :
          <DesktopLayout>{props.children}</DesktopLayout>
      )
}
Run Code Online (Sandbox Code Playgroud)