This is a series of my memo from when I migrated Next.js v13 into my project with the article From Pages to App. I also updated other packages’ versions.
Part1: Migrated app router from page router
Part3: Applied some other Next.js v13 updates
Optional: Updated NextAuth from v3 to v4
Optional: Updated Redux from classical Redux to Redux Toolkit Query
_app.js and _document.js → app/layout.js
These are main key points:
app directory supports nested routes and layout.
page.js is for defining a specific route UI
layout.js is for defining sharing UI among multiple routes
Suppose we have https:something and https:something/home, the folder structure of app directory will be:
app - layout.js // This layout will apply to all routes inside app
page.js
home - layout.js // The specific layout for home page
page.js
// Before
pages/_app.js
import { Provider } from "react-redux";
import { Provider as AuthProvider } from "next-auth/client";
import { wrapper } from "../redux/store";
import { useStore } from "react-redux";
import { PersistGate } from "redux-persist/integration/react";
import Head from "next/head";
import Layout from "../components/layout/layout";
import "semantic-ui-css/semantic.min.css";
import "../styles/globals.css";
function App({ Component, pageProps }) {
const store = useStore((state) => state);
return (
<AuthProvider session={pageProps.session}>
<Provider store={store}>
<Head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
{/* <link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"
crossOrigin="anonymous"
/>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> */}
<link
href="https://fonts.googleapis.com/css2?family=Italiana&family=Poiret+One&family=Spartan:wght@200;300;400;500;700&display=swap"
rel="stylesheet"
/>
</Head>
{process.browser ? (
<PersistGate
persistor={store.__persistor}
loading={<div>Loading</div>}
>
<Layout>
<Component {...pageProps} />
</Layout>
</PersistGate>
) : (
<PersistGate persistor={store}>
<Layout>
<Component {...pageProps} />
</Layout>
</PersistGate>
)}
</Provider>
</AuthProvider>
);
}
export default wrapper.withRedux(App);
// After
import ReduxProvider from "../client/providers/redux-provider";
import AuthProvider from "../client/providers/auth-provider";
import Layout from "../components/layout/layout";
import "semantic-ui-css/semantic.min.css";
import "../styles/globals.css";
function RootLayout({ children }) {
return (
<html lang="en">
<head>
<link
href="https://fonts.googleapis.com/css2?family=Italiana&family=Poiret+One&family=Spartan:wght@200;300;400;500;700&display=swap"
rel="stylesheet"
/>
</head>
<body>
<AuthProvider>
<ReduxProvider>
<Layout>{children}</Layout>
</ReduxProvider>
</AuthProvider>
</body>
</html>
);
}
export default RootLayout;
-> medadata
I don’t need to set charSet and viewport meta tags because these two are always added as the default (Default Fislds).
It is still necessary to import at app/layout.js as this metadata type currently doesn’t have build-in support(Unsupported Metadata)
metadata is only available for SSR
// Before
import { useSelector } from "react-redux";
import Head from "next/head";
import { getSession } from "next-auth/client";
import CheckoutList from "../../components/checkout-page/checkout-list";
import Message from "../../components/ui/message";
const ChackoutPage = () => {
const cartItems = useSelector((state) => state.cart.cartItems);
return (
<>
<Head>
<title>Checkout</title>
<meta name="description" content="Checkout Page" />
</Head>
<h1 className="h1">Checkout</h1>
{(!cartItems || cartItems.length === 0) && (
<Message text="No items added yet!" />
)}
{cartItems.length >= 1 && <CheckoutList list={cartItems} />}
</>
);
};
// After
// app/checkout/layout.js
export const metadata = {
title: "Checkout page",
};
export default function CheckoutLayout({ children }) {
return <>{children}</>;
}
Suspense and loading.js
loading.js and Suspense components from React provide you with a meaningful Loading UI.
Suspense provides better code optimization (Streaming Server Rendering and Selective Hydration).
You can make use of Instant Loading States when you put loading.js under the app router folder.
Here is an example.
// folder structure
app - layout.js // This layout will apply to all routes inside app
page.js
shop- [category]
[productId] - layout.js
page.js
loading.js
// layout.js
import { Suspense } from "react";
import Loading from "./loading";
export default function ProductLayout({ children }) {
return <Suspense fallback={<Loading />}>{children}</Suspense>;
}
javascript
references
https://nextjs.org/docs/app/api-reference/functions/generate-metadata
https://nextjs.org/docs/app/building-your-application/optimizing/metadata#seo
https://nextjs.org/docs/app/building-your-application/data-fetching/fetching
https://nextjs.org/docs/app/building-your-application/routing/loading-ui-and-streaming
original article is here
Top comments (0)