f.g.
f.g.

Reputation: 123

best practice for conditional rendering with SSR in Next.js

in my Next.js app i want to render a mobile-/ desktop-header based on the width of the device. In general this is a simple task, i did many times in normal react, using hooks like useWindowDimensions, where I check the width of the window object and use this parameter for a simple condition. In Next.js however I ran into the problem, that my app is pre-rendert on the server, so of course there is no window object, that I could use for the condition. Things I tried:

So, to make things short, there has to be a good way to render components in Next.js without the above problems. I just couldn't figure out yet, what is best practice for this kind of stuff.

I would appreciate any hints, tipps or advices in this topic ❤️

Upvotes: 3

Views: 1764

Answers (2)

Artemis Prime
Artemis Prime

Reputation: 183

I too had to render totally separate layout on desktop vs tablet / mobile. I also really wanted to take advantage of SSR.

So here's a solution that works well for me. I'm using Next 14, TS 5.2.2, and the newer app router, but this could also work with page router.

It's based on the the last approach listed above, and is the most bullet proof and "kosher" that I could find, but it does involve the downside of writing to search params.

  1. Examine user agent strings in middleware:
// src/middleware.ts
import { NextRequest, NextResponse, userAgent } from 'next/server'
import { getSelectorsByUserAgent } from 'react-device-detect'

export const middleware = async (request: NextRequest) => {

  const ua = userAgent(request)
  const { isMobileOnly, isTablet, isDesktop } = getSelectorsByUserAgent(ua.ua)
  const agent = isMobileOnly ? 'phone' : (isTablet ? 'tablet' : (isDesktop ?  'desktop' : 'unknown'))
  const { nextUrl: url } = request
  url.searchParams.set('agent', agent)
  return NextResponse.rewrite(url)
}
  1. Examine the searchParams in a route page:
// src/app/[slug]/page.tsx

import React from 'react'

import { Desktop, TouchDevice } from './scroll-snap'

  // From nextjs source 
type PageProps = {
  params: { slug: string };
  searchParams?: { [key: string]: string | string[] | undefined };
}

const Page: React.FC<PageProps> = ({ searchParams }) => {

    // see src/middleware.ts
  const agent = searchParams?.agent

  if (agent === 'desktop') {
    return <Desktop />
  }
  else if (agent === 'tablet') {
    return <TouchDevice isTablet={true} />
  }
  return <TouchDevice isTablet={false} />
}

export default Page

Upvotes: 0

Guest
Guest

Reputation: 1

It can be solved using css by creating 2 components, one for mobile, one for desktop and then hiding the mobile header on desktop view, hiding the desktop header on mobile view

Upvotes: -1

Related Questions