joplin-notes/joplin notion extension/Web Development/React/next/Coding 3.md
2026-11-04 00:33:23 +05:30

352 lines
No EOL
7.9 KiB
Markdown

Coding 3
**Link Component Navigation**
- To enable client-side navigation Next.js provides us with the Link component.
- The `<Link>` component is a React component that extends the HTML `<a>` element and is primary way for navigation
- To use it, we need to import it from 'next/link'.
Structure
```text
src/app
blog
page.jsx
products
page.jsx
page.jsx
```
In `src/app/page.jsx`
```jsx
import Link from "next/link";
const Home = () => {
return (
<>
<h1> Hello </h1>
<Link href="/blog">Blog</Link>
<Link href="/products">Products</Link>
</>
);
};
export default Home;
```
In `src/app/blog/page.jsx` `/` path is used to go to root page
```jsx
import Link from "next/link";
export default function Blog() {
return (
<>
<h1>Blog</h1>
<Link href="/">Home</Link>
</>
);
}
```
**For Dynamic Routes**
Structure
```text
src/app
blog
page.jsx
products
[productId]
page.jsx
page.jsx
page.jsx
```
In `src/app/products/page.jsx`
```jsx
import Link from "next/link";
export default function ProductList() {
const productId = 100;
return (
<>
<h1>Product List</h1>
<h2>Product 1</h2>
<h2>Product 2</h2>
<Link href={"products/3"} replace>
{" "}
<h2>Product 3</h2>{" "}
</Link>
<Link href={`products/${productId}`}>
{" "}
<h2>Product {productId}</h2>{" "}
</Link>
</>
);
}
```
- Link for Dynmaic routes is generated just like we access the value of variable.
With `replace` keyword we can clear the url stack history means after navigating to `localhost:3000/products/3` and when we click back button we will navigate to `localhost:3000` not `localhost:3000/products`.
&nbsp;
**Active Links**
- First we need to create links for login, register, forgot-password in layout.jsx page for `(auth)`. So instead of creating these 3 links for each page ie login, register and forgot-password we used layout.jsx to serve this as template/same for all route groups.
Structure
```text
src/app
(auth)
login
password
forgot-password
layout.jsx
page.jsx
```
In `src/app/(auth)/layout.jsx`
```jsx
import Link from "next/link";
const navLinks = [
{ name: "Register", href: "/register" },
{ name: "Login", href: "/login" },
{ name: "Forgot Password", href: "/forgot-password" },
];
export default function OuterAuthLayout({ children }) {
return (
<div className="">
{navLinks.map((link) => {
return <Link href={link.href}>{link.name}</Link>;
})}
{children}
</div>
);
}
```
- So in order to style it we need to know the path of current url so we need to use the `usePathname` from 'next/navigation' hook. As we r using hook we need client side rendering for this and have to type `use client` at top in jsx file.
Structure
```text
src/app
(auth)
login
password
forgot-password
layout.jsx
style.css
page.jsx
```
In `src/app/(auth)/layout.jsx`. Use the particular class for active link
```jsx
"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
import "./style.css";
const navLinks = [
{ name: "Register", href: "/register" },
{ name: "Login", href: "/login" },
{ name: "Forgot Password", href: "/forgot-password" },
];
export default function OuterAuthLayout({ children }) {
const pathname = usePathname();
return (
<div className="">
{navLinks.map((link) => {
const isActive = pathname.startsWith(link.href);
return (
<Link
href={link.href}
key={link.name}
className={isActive ? "active-link" : ""}
>
{link.name}
</Link>
);
})}
{children}
</div>
);
}
```
In `src/app/(auth)/style.css`
```css
a {
margin: 0 1rem;
color: blue;
}
a.active-link {
color: black;
}
```
&nbsp;
**Navigating Programitically**
- Instead of using jsx, javascript can be used too so for that we can use the hook ie `useRouter` from 'next/navigation'.
Structure
```text
src/app
order-product
page.jsx
page.jsx
```
In `src/app/order-product/page.jsx`
```jsx
"use client";
import { useRouter } from "next/navigation";
export default function OrderProduct() {
const router = useRouter();
const handleClick = () => {
console.log("order placed");
router.push("/");
};
return (
<>
<h1>Order Product</h1>
<button onClick={handleClick}>Place Order</button>
</>
);
}
```
router.push('/') will push the root route to url stack and when we click on back after going through homepage it will brink back to the page `localhost:3000/order-product`. In `Link` coponent there was a attribute named replace which clears the url stack so to do same programitically use `router.replace('/')`. Not only that but we can go to previous or next url stack too by `router.back()` and `router.forward()`
&nbsp;
**Templates**
- Templates are similar to layouts in the way they wrap each child layout or page
But with templates when a user navigates between routes that share a template, a new instance of component is mounted, DOM elements are recreated, state is not preserved.
- So to only to be used once we dont have to conserve states and need a template to recreate pages so their states dont conflict with each other
Without template
```text
src/app
(auth)
login
password
forgot-password
layout.jsx
style.css
page.jsx
```
In `src/app/(auth)/layout.jsx`
```jsx
"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
import "./style.css";
import { useState } from "react";
const navLinks = [
{ name: "Register", href: "/register" },
{ name: "Login", href: "/login" },
{ name: "Forgot Password", href: "/forgot-password" },
];
export default function OuterAuthLayout({ children }) {
const pathname = usePathname();
const [input, setInput] = useState("");
return (
<div className="">
<div className="">
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
/>
</div>
{navLinks.map((link) => {
const isActive = pathname.startsWith(link.href);
return (
<Link
href={link.href}
key={link.name}
className={isActive ? "active-link" : ""}
>
{link.name}
</Link>
);
})}
{children}
</div>
);
}
```
When we move to new route input will be same and wont be reset.
**With templates**
Just change the file name from layout.jsx to template.jsx and now input will be reset and nothing will be preserved.
Some limitations though. If there is a route group(say named inner-auth) like this
Structure
```text
src/app
(auth)
(inner-auth)
login
password
forgot-password
template.jsx
style.css
page.jsx
```
In this case, states between `login` and `password` routes will be shared not with `forget-password` route though.
&nbsp;
**Loading UI**
- Till now different files like `page.jsx`, `layout.jsx`, `not-found.jsx` and `template.jsx` have been used. There is another one ie `loading.jsx`.
Structure
```text
src/app
blog
first
second
loading.jsx
layout.jsx
page.jsx
page.jsx
```
In `src/app/blog/loading.jsx`
```jsx
export default function LoadingBlog() {
return (
<div className="LoadingBlog">
<h1>Loading</h1>
</div>
);
}
```
To test it, make sure that `src/app/blog/page.jsx` loads slower due to setTimeout. Make sure that layout.jsx wont load slow as first layout.jsx is loaded then loading.jsx contents then page.jsx.
In `src/app/blog/page.jsx`
```jsx
import Link from "next/link";
export const metadata = {
title: {
absolute: "blog",
default: "blog",
},
};
function promiseSetTimeOut(time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, time);
});
}
export default async function Blog() {
await promiseSetTimeOut(1000);
return (
<>
<h1>Blog</h1>
<Link href="/">Home</Link>
</>
);
}
```