Work Hours
Monday to Friday: 8am – 6pm
Weekend: 10am – 2pm
In this chapter, we will focus on layouts, navigation with highlighting active link, images and rendering.
Layout define how our pages will be formatted. It is shared between every page in path and sub path. It can be overridden by defining a new layout in the folder. Layout is of course a file, named: layout. We need at least one layout in root folder of application. Usually it contains header, content placement and footer. It is good place to have navigation of application as it will be constant to every page, that layout is applied.
Minimal root layout would be looking like this.
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
Layouts inside sub folders are nested. Which means, child layouts are wrapped by children properties. Notice that only root layout can contain <html> and <body> tags.
Another handy file is template. It is very similar to layout, but it persists across routes and handle state. Template can use useEffect and useState. The simplest template would look like:
export default function Template({ children }: { children: React.ReactNode }) {
return <div>{children}</div>
}
Final code, including layout, will be resolved to this.
<Layout>
{/* Note that the template is given a unique key. */}
<Template key={routeParam}>{children}</Template>
</Layout>
To keep navigation simple, next.js defines component <Link>. It requires href parameter. Using dynamic linking, we can easily create dynamic links, like:
<Link href={`/blog/${post.id}`}>{post.title}</Link>
Not every time, we can use Link component to navigate. When we need to change route from code, we can use Router. It is simple useRouter hook.
It can navigate in several differnet ways.
const router = useRouter();
router.push("/"); // add to browser stack and redirect
router.replace("/"); // not use history browser stack
router.refresh(); // refresh from server
router.back(); // move back in browser stack
router.forward(); // move forward in browser stack
There is good to know sometimes, when we are in our routing through page. For example, when we are writing a navigation component, and we need to know if we should highlight the current page. For this, we have usePathname from “next/navigation“. To get parameters of navigation url, we should use useSearchParams. For sample address: http://localhost/post?id=1234, usePathname returns post, useSearchParams returns 1234. It works on client side.
For server side component, when we define our App Route as [id], we can extract it accordingly.
const Page = ({params, searchParams}) => {
// params = { id: 'post' }
// searchParams = { q: '1234' }
}
Next.js defines a component <Image> to easily maintain images. This component requires several parameters to work correctly. The most important parameter is src. It defines, what will be displayes. It can be url, local path or base64 string.
When we are linking external urls, we need to whitelist them using next.config.js file.
images: {
remotePatterns: [{
protocol: 'https',
hostname: 'address.com'
}]
}
Getting back to parameters. We need to define alt string. It is generally good practice to always set this prop even we are using simple <img> tag.
To proper display image, there is needed to define width and/or height. Those two are required. There is an exception to that rule. When we define fill={true} property for statically imported image, we can skip those two params. We can also skip them, if we have wrapping div with defined sizes and position style is one of: relative, fixed or absolute, and fill={true}.
<div className="w-full h-64 relative">
<Image src={post.image} fill={true} alt="image" />
</div>
Rendering converts code to HTML. This process could be at server side or client side. Both have pros and cons. I will not go into details, because it is good enough explained in documentation. I would like to share the most important thing about both methods and summary when use which method.
When a user is sending a request for a page, the browser sends the request to the server. The server renders the static HTML page, adds interactive JavaScript and sends it back to the browser.
Pros:
Cons:
When a user is sending a request for a page, the browser sends the request to the server. The server sends an empty HTML page and whole JavaScript application. Next, the browser is rendering the page to finally who it to the user.
Pros:
Cons:
Next.js can take advantages from both worlds. You can have one component, which is server side. It can contain other component at client side and this component can have third component which is server side. This provides us every pros from both worlds and minimize cons.
Client side component:
"use client"
const ClientSideComponent = ({children}) => {
return (
<div>
{children}
</div>
)
}
export default ClientSideComponent
Server side component:
<ClientSideComponent>
<div>server data</div>
</ClientSideComponent>
In the next chapter, I will write about fetching data in two ways: Server Action and API. Stay tuned.
The whole example project can be found here.