This content originally appeared on Level Up Coding - Medium and was authored by Itsuki
Next.js: Migrating app.tsx (Pages Router) to layout.tsx (App Router)
Of course, there are lots of other things you will have to do while upgrading from Pages to App.
You will have to upgrade Next.js version to 13, ESLint version if you are using it, change your router imports and many more!
In this article, we will be focusing on migrating _document.js and _app.js to layout.tsx, especially on how we can handle our Context Providers.
Set Up
Couple steps here before we can start working on migrating our app.tsx and document.tsx.
- Create an app directory. If you are using src directory, this will be under that.
- Create a new app/layout.tsx file inside the app directory
- Create a new app/providers.tsx file inside the app directory
Before
I think it will be more straightforward to work with an example, so let’s start with a basic _app.tsx and _document.tsx here.
app.tsx
In addition to the super basic app.tsx, I have also added some custom contexts.
import '@/styles/globals.css'
import type { AppProps } from 'next/app'
import React from 'react'
import { UserContext, UserService } from "./lib/UserService";
import Loading from '@/components/loading'
import Head from 'next/head'
export default function App({ Component, pageProps }: AppProps) {
const [userId, setUserId] = React.useState<string|null>(null);
React.useEffect(() => {
const userId = userService.getUserId()
setUserId(userId)
}, []);
const value = React.useMemo(() => (
{userId: userId, dispatch: setUserId}
), [userId, setUserId])
return (
<>
{
isLoading ?
<Loading /> :
<UserContext.Provider value = {value}>
<Component {...pageProps} />
</UserContext.Provider>
}
</>
)
}
document.tsx
Within our document.tsx, we will have some meta data defining viewports, descriptions, titles, and etc.
import { Html, Head, Main, NextScript } from 'next/document'
export default function Document() {
return (
<Html lang="en">
<Head>
<meta name="viewport" content="initial-scale=1, viewport-fit=cover, width=device-width"></meta>
<meta name="description" content="Free Web tutorials">
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
After
Time to migrate!
layout.tsx
Let’s start with our layout.tsx.
We can copy most of the contents such as global styles to the root layout app/layout.tsx. Also, we can user the built-in SEO support to help us manage the <head> elements, taking the meta tag here as an example.
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import { Providers } from "./provider";
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "some title",
description: "some description",
};
export default function RootLayout({children}: Readonly<{children: React.ReactNode;}>) {
return (
<html lang="en">
<body className={inter.className}>
<Providers>{children}</Providers>
</body>
</html>
);
}
Ignore the Providers here, we will be getting more details into it in couple seconds!
Before that, there are just couple notes I would like to make here.
First of all, view port is default to the following. Unless you want to overwrite it, you can leave it out.
viewport: {
width: 'device-width',
initialScale: 1,
maximumScale: 1,
},
Also, if you want to set a different page title using the exported metadata in other layouts, you can define it using a template. For example, if we want our title to be of form title | AppName, we can do the following.
export const metadata = {
title: {
template: '%s | some App Name',
},
description: 'description',
}
Last and MOST IMPORTANT, we are removing all the React hooks here. This is because our layout.tsx is a Server Component and in order for us to use Context providers, we will need a Client Component which is exactly what our providers.tsx for!
providers.tsx
use client!
We can then simple move the context providers that are originally in our app.tsx here, export the Providers and use it within our layout.tsx.
'use client'
import { UserContext, UserService } from "./lib/UserService";
import React from "react";
const userService = new UserService()
export function Providers({ children }: { children: React.ReactNode }) {
const [userId, setUserId] = React.useState<string|null>(null);
React.useEffect(() => {
const userId = userService.getUserId()
setUserId(userId)
}, []);
const value = React.useMemo(() => (
{userId: userId, dispatch: setUserId}
), [userId, setUserId])
return (
<>
{(userId === null) ?
<></> :
<UserContext.Provider value={value}>
{children}
</UserContext.Provider>
}
</>
);
}
That’s it!
Thank you for reading!
Happy migrating!
NextJs: Migrating app.tsx(Pages Router) to layout.tsx(App Router) was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.
This content originally appeared on Level Up Coding - Medium and was authored by Itsuki
Itsuki | Sciencx (2024-09-02T00:41:56+00:00) NextJs: Migrating app.tsx(Pages Router) to layout.tsx(App Router). Retrieved from https://www.scien.cx/2024/09/02/nextjs-migrating-app-tsxpages-router-to-layout-tsxapp-router/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.