App router is mixture of multiple page and single page application
Each path has their own html page but when using next/link, the javascript will be loaded instead of html file
The initial page will be rendered on server, but for user interaction (e.g: useState, useEffect) , the page is needed to be hydrated with javascript file
Server & Client Side Component
When html page of Nextjs is loaded, the static content and data of of server component will be pre-rendered and fetched
The data of client component will then be hydrated through built javascript file
// Next.js fetch API in action
async function loadPosts() {
const res = await fetch("https://jsonplaceholder.typicode.com/posts");
/*
* Since this is a server component, the below message
* won't be displayed in the browser's dev console.
*/
console.log("Server Component fetching");
// return res.json();
return ["this is server component"];
}
// Next.js will invalidate the cache when a
// request comes in, at most once every 60 seconds.
export const revalidate = 60
const ServerComponent = async () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const posts:any[] = await loadPosts();
return (
<div className="post-list">
Server Component
{posts.map((post) => (
<div key={post} className="post-listing">
<p className="post-body">{post}</p>
</div>
))}
</div>
);
};
export default ServerComponent;
Result
Link Navigation
import Link from "next/link"
import ClientComponent from "../components/ClientComponent"
const OtherPage = () => {
return (
<div>
<ClientComponent/>
<Link href={"/"}>Back Home</Link>
</div>
)
}
export default OtherPage
If using Link instead of a tag for navigation. On UI level, it will be shown as a tag, but it will execute client side navigation behind the scene,
If the page contains server component, only RSC payload will be fetched, which is the result of server-side rendering and the position of client-side component with corresponding javascript file
Backend API
Nextjs can be used to act as full stack development, here is the example of implementing backend part. The file must be route.ts/js
When using fetch api on Nextjs, there are several caches existing - request memoization, data cache
Request memoization
If you need to use the same data across a route, e.g using the same component, you do not have to fetch data in every time. Instead, it will fetch data once.
The cache lasts the lifetime of a server request until the React component tree has finished rendering.
import Link from "next/link";
import ServerComponent from "./components/ServerComponent";
export default function Home() {
return (
<>
<ServerComponent/>
<ServerComponent/>
<Link href="/other">Go to other</Link>
</>
);
}
default: Nextjs fetching will be treated same as force-cache, unless revaildate is specified
no-store: Next.js fetches the resource from the remote server on every request without looking in the cache, and it will not update the cache with the downloaded resource.
force-cache: Next.js looks for a matching request in its Data Cache.
If there is a match and it is fresh, it will be returned from the cache.
If there is no match or a stale match, Next.js will fetch the resource from the remote server and update the cache with the downloaded resource.
Incremental Static Regeneration (ISR)
The data of cache will be stale after a period of time, and the data will be obtained from data source rather than cache
import React from 'react'
import TestCompoent from './components/test'
import Link from 'next/link'
const Main = () => {
return (
<div>
Main Page
</div>
)
}
export default Main
layout.tsx
"use client"
import React from "react"
export default function Layout({
user,
children, // will be a page or nested layout
}: {
children: React.ReactNode
user: React.ReactNode
}) {
return (
<>
/* User */
{user}
/* Main */
{children}
</>
)
}