NextJS recently released version 13.4, which stabilizes the App Router and changes it to the default and recommended solution in the official CLI. However, the App Router introduces the concept of React Server Components (referred to as RSC) and changes a significant number of APIs, making it more difficult to learn.
Server Components#
In the App Router, NextJS distinguishes between Client Components and Server Components. Server Components are a special type of React component that runs on the server-side instead of the browser. Because they don't have state, they cannot use client-side features like useState and useEffect. They are typically used for data fetching or rendering components that have JavaScript dependencies only available on the client-side, such as rendering markdown, to reduce client-side bundle size.
By default, all files in the App Router are server components. If you want to use client components, you need to add the "use client" directive. However, this directive affects all child components as well. For example, if the parent component has the "use client" directive, all child components in that file will be treated as client components. To address this, it is recommended to plan the layout and separate client components using Layout.
The following <MyComponent />
is an example of a client component:
"use client";
import { useState } from "react";
import MyComponent from "./MyComponent";
export default function Home() {
const [num, setNum] = useState(0);
return (
<main>
<h1>{num}</h1>
<button onClick={() => setNum(num + 1)}>+1</button>
<MyComponent />
</main>
);
}
import { useEffect } from "react";
const MyComponent = () => {
useEffect(() => {
console.log("client component");
}, []);
return <div>123</div>;
};
export default MyComponent;
Additionally, many third-party libraries do not support the "use client" directive, resulting in errors.
To use libraries like framer-motion in RSC, special handling is required. For example, you can wrap the component with motion.div:
"use client"
import { FC, PropsWithChildren } from "react";
import { motion } from "framer-motion";
const MotionLayout: FC<PropsWithChildren> = ({ children }) => {
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5 }}
>
{children}
</motion.div>
);
};
export default MotionLayout;
Or you can create a wrapper component:
"use client"
import { motion } from "framer-motion";
export const MotionDiv = motion.div;
Data Fetching#
Fetching data is an important aspect of RSC. You can fetch data as follows:
export default async function Home() {
const data = await fetch("https://api.github.com/repos/vercel/next.js").then(
(res) => res.json()
);
return <div>{data.id}</div>;
}
However, note that this code defaults to Static Site Generation (SSG). To enable Server-Side Rendering (SSR), you need to add the "cache" configuration:
export default async function Home() {
const data = await fetch("https://api.github.com/repos/vercel/next.js", {
cache: "no-store",
}).then((res) => res.json());
return <div>{data.id}</div>;
}
You can also use Incremental Static Regeneration (ISR) by specifying the revalidate interval:
// ISR refreshes every 10 seconds
export default async function Home() {
const data = await fetch("https://api.github.com/repos/vercel/next.js", {
next: {
revalidate: 10,
},
}).then((res) => res.json());
return <div>{data.id}</div>;
}
If you prefer to use libraries like axios for SSR, you can write the following code:
import axios from "axios";
export const dynamic = "force-dynamic";
export default async function Home() {
const { data } = await axios.get(
"https://api.github.com/repos/vercel/next.js"
);
return <div>{data.id}</div>;
}
Routing#
The App Router enhances the routing capabilities. You can group routes using (folderName)
notation, where the group name is not mapped to the actual route. This improves code readability and allows for shared layouts.
Dynamic routes can be defined using [folderName]
notation, and the corresponding values can be accessed in the props.
You can create a loading.tsx
component that wraps Suspense to display content while fetching data in the page.tsx
component.
Similarly, an error.tsx
component can be used to handle rendering errors and prevent a blank screen.
Parallel Routes allow you to map @folderName
to the layout props, acting as "slots" for components like headers and footers.
export default function Layout(props: {
children: React.ReactNode;
analytics: React.ReactNode;
team: React.ReactNode;
}) {
return (
<>
{props.children}
{props.team}
{props.analytics}
</>
);
}
In conclusion, the App Router has many APIs, and the examples provided are just a small portion. It is recommended to refer to the official documentation for more details.
This article is synchronized and updated to xLog by Mix Space.
The original link is https://suemor.com/posts/programming/approuter