-
-
Save buddalee/d3d7a46cfab71e072fb6c3bed074bc58 to your computer and use it in GitHub Desktop.
Nextjs in server side to detect device with user agent |
static async getInitialProps ({ Component, ctx }) { | |
const isServer = !!ctx.req | |
const userAgent = isServer | |
? ctx.req.headers['user-agent'] | |
: navigator.userAgent | |
const isLine = /\bLine\//i.test(userAgent) || false | |
const isMobile = /(iPad|iPhone|Android|Mobile)/i.test(userAgent) || false | |
const rules = [ | |
'WebView', | |
'(iPhone|iPod|iPad)(?!.*Safari/)', | |
'Android.*(wv|.0.0.0)' | |
] | |
const regex = new RegExp(`(${rules.join('|')})`, 'ig') | |
const isInApp = Boolean(userAgent.match(regex)) | |
console.log('=================') | |
console.log('userAgent: ', userAgent) | |
console.log('isLine: ', isLine) | |
console.log('isMobile: ', isMobile) | |
console.log('isInApp: ', isInApp) | |
console.log('=================') | |
} |
Just want to say that I am using this and thank you!
When using a hook that works of the window size it causes elements to jump in on page load which is not okay. This should be the offered solution on all the forums.
For app router:
I wanted to pre-render a page conditionally based on the device type on React/NextJS/SSR. I was able to do it by storing the user-agent in a context and reading it from a hook useIsMobile()
which returned true or false based on the parsed user-agent header on the server side.
We create a context to store the parsed user-agent header.
// userAgentContext.ts
import { userAgent } from "next/server";
import { createContext } from "react";
export type UserAgent = ReturnType<typeof userAgent>;
export const UserAgentContext = createContext<UserAgent | undefined>(undefined);
We create a hook to consume the context and check device type.
// useIsMobile.ts
import { useContext } from "react";
import { UserAgentContext } from "./userAgentContext.ts";
export const useIsMobile = () => {
const userAgent = useContext(UserAgentContext);
if (!userAgent) {
throw new Error("useIsMobile must be used within a UserAgentContext.Provider");
}
return userAgent.device.type === "mobile";
};
We can use a sever component as the layout (app router) to get the user agent from request headers
// layout.tsx
"use server";
import { headers } from "next/headers";
import { userAgent } from "next/server";
import { LayoutClient } from "./layoutClient.ts";
export default async function Layout({ children }: { children: React.ReactNode }) {
const reqUserAgent = userAgent({ headers: headers() });
return <LayoutClient reqUserAgent={reqUserAgent}>{children}</LayoutClient>
}
We can then pass the user agent to a client component that will provide the initial value for the context. Since client components with "use client"
directive are still rendered once on the server with initial values then hydrated on the client.
// layoutClient.tsx
"use client";
import { UserAgentContext } from "./userAgentContext.ts";
export default function LayoutClient({ reqUserAgent, children }: { reqUserAgent: UserAgent, children: React.ReactNode }) {
return <UserAgentContext.Provider value={reqUserAgent}>{children}</UserAgentContext.Provider>;
}
Now when this page is rendered for the first time on the server with initial values, useIsMobile() should accurately return a value based on the user-agent device type.
// page.tsx
"use client";
export default function Page() {
const isMobile = useIsMobile();
return isMobile ? <>Mobile</> : <>Desktop</>;
}
It's a chat application name which is popular in Taiwan and Japan.
The code trace request whether come from mobile browser or line application In-App browser
=> https://line.me/en/