initial
This commit is contained in:
commit
74ae93a96e
1 changed files with 94691 additions and 0 deletions
352
joplin notion extension/Web Development/React/next/Coding 3.md
Normal file
352
joplin notion extension/Web Development/React/next/Coding 3.md
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
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`.
|
||||
|
||||
|
||||
**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;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
**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()`
|
||||
|
||||
|
||||
**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.
|
||||
|
||||
|
||||
**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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
Loading…
Reference in a new issue