This commit is contained in:
nm1 2026-11-04 00:33:23 +05:30
commit 74ae93a96e
14 changed files with 94691 additions and 0 deletions

View file

@ -0,0 +1,93 @@
Advanced
- server actions
able to use forms in server component
https://inv.in.projectsegfau.lt/watch?v=Yc2MJYwLqzs
- sending form data
https://nextjs.org/docs/pages/building-your-application/data-fetching/forms-and-mutations
https://www.youtube.com/watch?v=AbLAxs-7yl0
for `application/x-www-form-urlencoded`
just use
```jsx
<form action="/route/api" method="POST">
<input type="text" name="city">
</form>
const onSubmit = async (e) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const response = await fetch("/addschool/api", {
method: "POST",
body: formData,
});
};
```
this will just Formdata which is not multipart but of urlencoded and field will be `city`
for multipart form data
```html
<form onSubmit={onSubmit}>
<input type="text" name="city">
</form>
```
- receiving form data
```js
import { redirect } from "next/navigation";
import fs from "fs";
export async function POST(request) {
// console.log("request: ", request.body);
const formData = await request.formData();
console.log(formData);
const number = formData.get("contactNumber");
const file = formData.get("imageAttachment");
const fileBuffer = Buffer.from(await file.arrayBuffer());
console.log("fileBuffer: ", fileBuffer);
fs.writeFileSync(file.name, fileBuffer);
console.log("number ", number);
redirect("/addschool");
}
```
- uploading file in vercel blob
https://vercel.com/brads-projects-55888f01/~/stores/blob/store_I4WjQqMnSOkFDxWt/guides
- standalone builds
node modules may contain lot of modules that are not required so
1. configure next.config.js like this
```js
module.exports={
output : "standalone"
}
```
2. then at dist there is standalone folder is created go to that folder and do `npm i` and then go to root directory
3. Remove the output standalone config and then build it again to have folder `.next`, copy this folder in standalone directory and when running `npm run start` it will run this build
- remove type errors in nextjs build
```js
// in next.config.js
module.exports = {
typescript: {
// !! WARN !!
// Dangerously allow production builds to successfully complete even if
// your project has type errors.
// !! WARN !!
ignoreBuildErrors: true,
},
}
```

View file

@ -0,0 +1,486 @@
Coding 10 Data fetching
Data Fetching
- Server components support various configurations for caching, revalidating and optimizing data fetching
- Client components have to use third party libraries such as TanStack Query which offers robus APIs
Structure
```text
src/app
users
page.jsx
page.css
```
In `src/app/users/page.jsx`
```js
import "./page.css";
function User(props) {
const { id, name, username, email, phone } = props;
return (
<div key={id} className="user">
<div className="col1">
<div>{name}</div>
<div>{username} </div>
</div>
<div className="col2">
<div className="">{email}</div>
<div className="">{phone}</div>
</div>
</div>
);
}
export default async function UsersPage() {
console.log("UsersPage loaded");
const response = await fetch("https://jsonplaceholder.typicode.com/users");
const users = await response.json();
console.log(users);
return (
<div className="UsersPage">
{users.map((user) => (
<User
id={user.id}
name={user.name}
username={user.username}
email={user.email}
phone={user.phone}
/>
))}
</div>
);
}
```
In `src/app/users/page.css`
```css
body {
background: rgb(20, 20, 20);
}
.UsersPage {
text-align: left;
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 2rem;
padding: 4rem;
margin: auto;
}
.UsersPage .user {
min-width: 350px;
width: 60%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
background: white;
margin: auto;
border: 1px solid grey;
border-radius: 5px;
}
.UsersPage .user .col1,
.UsersPage .user .col2 {
display: flex;
flex-direction: column;
/* align-items: center; */
flex-grow: 1;
}
.UsersPage .user .col2 {
align-items: end;
}
```
&nbsp;
**Loading and Error States**
Structure
```text
src/app
users
page.jsx
page.css
error.jsx
loading.jsx
```
In `@/users/page.jsx`
```js
import { resolve } from "styled-jsx/css";
import "./page.css";
function User(props) {
const { id, name, username, email, phone } = props;
return (
<div key={id} className="user">
<div className="col1">
<div className="font-bold">{name}</div>
<div>{username} </div>
</div>
<div className="col2">
<div className="">{email}</div>
<div className="">{phone}</div>
</div>
</div>
);
}
export default async function UsersPage() {
await new Promise((resolve) => setTimeout(resolve, 2000));
console.log("UsersPage loaded");
const response = await fetch("https://jsonplaceholder.typicode.com/users1");
const users = await response.json();
console.log(users);
return (
<div className="UsersPage">
{users.map((user) => (
<User
id={user.id}
name={user.name}
username={user.username}
email={user.email}
phone={user.phone}
/>
))}
</div>
);
}
```
In `@/users/page.css`
```css
body {
background: rgb(20, 20, 20);
}
.UsersPage {
text-align: left;
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 2rem;
padding: 4rem;
margin: auto;
}
.UsersPage .user {
min-width: 350px;
width: 60%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
background: white;
margin: auto;
border: 1px solid grey;
border-radius: 5px;
}
.UsersPage .user .col1,
.UsersPage .user .col2 {
display: flex;
flex-direction: column;
/* align-items: center; */
flex-grow: 1;
}
.UsersPage .user .col2 {
align-items: end;
}
```
In `@/users/loading.jsx`
```js
export default function LoadingPage() {
return (
<div className="flex items-center justify-center h-screen">
<div className="animate-spin rounded-full h-32 w-32 border-t-2 border-b-2 border-white"></div>
</div>
);
}
```
In `@/users/error.jsx`
```js
"use client";
import { useEffect } from "react";
export default function ErrorPage({ error }) {
useEffect(() => {
console.error(`${error}`);
}, [error]);
return (
<div className="flex items-center justify-center h-screen">
<div className="text-2xl text-red-500">Error fetching users data</div>
</div>
);
}
```
&nbsp;
**JSON Server Setup**
- Install npm package `json-server@0.17.4`. Make sure that this is the version
- At the root of project create 2 files named `db.json` and `server.js`.
In `db.json`type
```json
{
"products": [
{
"id": 1,
"title": "Product 1",
"price": 800,
"description": "Description 1"
},
{
"id": 2,
"title": "Product 2",
"price": 1000,
"description": "Description 2"
},
{
"id": 3,
"title": "Product 3",
"price": 2500,
"description": "Description 3"
}
]
}
```
In `server.js`
```js
const jsonserver = require("json-server");
const server = jsonserver.create();
const PORT = 3002;
const router = jsonserver.router("./db.json");
const middlewares = jsonserver.defaults();
server.use(middlewares);
server.use((req, res, next) => {
console.log("request recieved");
res.header("Access-Control-Allow-Origin", "*");
res.header(
"Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, PATCH, OPTIONS"
);
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
next();
});
server.use(router);
server.listen(PORT, () => {
console.log("JSON Server is running");
});
```
As port is 3002 so when we visit to `localhost:3002/products`. we get array of products
&nbsp;
Caching Data
- By default, Next.js automatically catches the returned values of fetch in the Data Cache on the server.
In `src/app/products/page.jsx`
```js
import "./page.css";
export default async function Products() {
console.log("Products loaded");
const response = await fetch("http://localhost:3002/products");
const products = await response.json();
return (
<ul className="Products space-y-4 p-4">
{products.map((product) => (
<li className="p-4 bg-white shadow-md rounded-lg text-gray-700">
<h2 className="text-xl font-semibold">{product.title}</h2>
<p>{product.description}</p>
<p className="text-lg font-medium">{product.price}</p>
</li>
))}
</ul>
);
}
```
&nbsp;
**Data Cache**
- It is a server-side cache that persists the result of data fteches across incoming server requests and deployments
- It improves app performance and reduce costs by eliminating need to refetch data from data source with every request
- ![8d6701c74b6fe0c0c8e567dba819b36c.png](../../../../_resources/8d6701c74b6fe0c0c8e567dba819b36c.png)
- When request is made instead of getting information from data source it checks if its exist on cache. If it does exist then it simply returns it otherwise it will get data from source, send back to client also saving it in cache.
- This data cache is stored in `.next/cache`. One such is `fetch-cache` in this folder. It contains cached data of the routes.
- Unlike browser cache this is server cache means even if we load this page in different browser or incognito mode we get same result
- If we clear the cache file and restart json and next dev server then we will get updated value
&nbsp;
**Opt out of caching**
- To simply opt out of caching when fetching, set field `cookie` as `no-store`.
eg
```js
const response = await fetch("http://localhost:3002/products", {
cache: "no-store",
});
```
- When using `no-store` all subsequent fetch requests will also be out out of caching too so its wise to place those fetch requests where caching is needed to use before then those where caching is opted out
- There is a workaround to use cache even after using it after fetch request with `cache` set as `no-store`
Type the following at top of the code
`export const fetchCache = "default-cache";`
This is route level
https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#fetchcache
Eg: In `src/app/products/page.jsx`
```js
import "./page.css";
export const fetchCache = "default-cache";
export default async function Products() {
console.log("Products loaded");
const response = await fetch("http://localhost:3002/products", {
cache: "no-store",
});
const products = await response.json();
const detailedResponse = await fetch("http://localhost:3002/products/1");
const detailedData = await detailedResponse.json();
console.log("detailedata: ", detailedData);
return (
<ul className="Products space-y-4 p-4">
{products.map((product) => (
<li className="p-4 bg-white shadow-md rounded-lg text-gray-700">
<h2 className="text-xl font-semibold">{product.title}</h2>
<p>{product.description}</p>
<p className="text-lg font-medium">{product.price}</p>
</li>
))}
</ul>
);
}
```
Other values of fetchCache
```js
export const fetchCache = 'auto'
// 'auto' | 'default-cache' | 'only-cache'
// 'force-cache' | 'force-no-store' | 'default-no-store' | 'only-no-store'
```
- Another way is using dynamic functions ( cookies(), headers(), searchParams ). Make sure to use them before making fetch requests. fetch requests before using dynamic functions will be cached by dedault though
Eg:
```js
import { cookies } from "next/headers";
import "./page.css";
// export const fetchCache = "default-cache";
export default async function Products() {
console.log("Products loaded");
const cookieStore = cookies();
cookieStore.get("sd");
const detailedResponse = await fetch("http://localhost:3002/products/1");
const detailedData = await detailedResponse.json();
const response = await fetch("http://localhost:3002/products", {
cache: "no-store",
});
const products = await response.json();
console.log("detailedata: ", detailedData);
return (
<ul className="Products space-y-4 p-4">
{products.map((product) => (
<li className="p-4 bg-white shadow-md rounded-lg text-gray-700">
<h2 className="text-xl font-semibold">{product.title}</h2>
<p>{product.description}</p>
<p className="text-lg font-medium">{product.price}</p>
</li>
))}
</ul>
);
}
```
&nbsp;
**Request Memoization** (Client-side caching)
- It is a technique that deduplicates requests for the same data within a single render pass. This feature is by default
- This approach allows for re-use of data in a React Component tree, prevents redundant network calls
- After data is fetched initially, result is stored in memory
- When same data is needed across different components in a rout( eg in a layout, page and multiple components ), it eliminates the need to fetch data a the top of tree
Structure
```text
src/app
products
layout.jsx
page.jsx
```
In `src/app/products/layout.jsx`
```js
export default async function LayoutPage({ children }) {
const productresponse = await fetch("http://localhost:3002/products");
const data = await productresponse.json();
console.log("product data :", data);
console.log("Product LayoutPage loaded");
return <>{children};</>;
}
```
this url is fetched in page.jsx too but at json server this route is accessed one time only bcz layout.jsx and page.jsx is in single render pass
- ![f2ea8455f4a7eb8c141ec7f64752c652.png](../../../../_resources/f2ea8455f4a7eb8c141ec7f64752c652.png)
- When request is made it checks memory for the result. If not then it goes to server and in server it checks data cache then it checks data source.
&nbsp;
Note: Its not limited to client side bcz components can be server component too
&nbsp;
Imp notes about it
- Request memoization is a React future and not limited to nextjs. In React 19 request memization will no longer be default feature. So its possible then in future it will be no longer by default too
- Memoization only applies to GET method in fetch requests.
- It applies to react component tree and not extend to route handlers as they are not part of react component tree
- For cases where fetch is not suitable (eg some database clients, CMS clients or GraphQL clients), we can use the React cache function to meoize functions.

View file

@ -0,0 +1,235 @@
Coding 2
**Private Folders**
- In nextjs routing is based on folders so things like grouping and management for code is also done by project so there have to be folders which is not routable or write ui logic rather than routing logic. These folders r called private folders.
- They begin with `_`(underscore). eg: `_lib`.
- If we want underscore to be as part of route then use the prefix `%5F` which is url encoded form of underscore(`_`).
&nbsp;
**Route Groups**
- Allows us to logically group our routes and project files without affecting the URL path structure.
- Folder purpose is not for routing only but for grouping of various routes and we may not want to effect the url. Example if project structure
```text
src/app
auth
Login
Register
page.jsx
````
To access we need `localhost:3000/auth/register`. If we want to access via `localhost:3000/register` then we need to tell next that `auth` is route group. surround auth with parenthesis like this `(auth)`.
Now
```text
src/app
(auth)
Login
Register
page.jsx
````
&nbsp;
**Layout**
- A page is UI that is unique to a route
- A layout is UI that is shared between multiple pages in the app.
Eg:
In `src/app/layout.jsx`
```jsx
export const metadata = {
title: "Next.js",
description: "Generated by Next.js",
};
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<header style={{ background: "lightblue", padding: "1rem" }}>
Head
</header>
{children}
<footer style={{ background: "orange", padding: "1rem" }}>
Footer
</footer>
</body>
</html>
);
}
```
Now every page.jsx content will be under this header and footer. and the routes ie folder inside app and all those nested one will inherit too
&nbsp;
**Route Group Layout**
- We may not want the same layout for every nested route so to fix it we can use route groups for layout. Purpose being is to selectively apply layout to certain segments while leaving other unchanged
Structure
```text
src/app
(auth)
forgot-password
(with-auth-layout)
Login
Register
layout.jsx
page.jsx
```
In `src/app/(auth)/(with-auth-layout)/layout.jsx` .
```jsx
export default function AuthLayout({ children }) {
return (
<div className="">
<h2>Inner Layout</h2>
{children}
</div>
);
}
```
Now in `login` and `register` we would have
```text
Head
Inner Layout
Login
Footer
```
This inner layout is added for login and password only and wont work for forgot-password page
&nbsp;
**Routing metadata**
- Nextjs have metadata api to define metadata for each page
- Medadata ensures accurate and relevant information is displayed when the page is shared or indexed.
- Configuring metadata
- Export static metadata object
- Export a dynamic generateMetadata function
**MetaData Rules**
- Both layout.jsx and page.jsx files can export metadata. If defined in a layout, it applies to all pages in that layout, but defined in a page, then that page only.
- Metadata is read in order ie from root level to final page level.
- When there's metadata in multiple places for the same route, they get combined, but page metadata will replace layout metadata if they have the same properties
Structure
```text
src/app
about
page.jsx
page.jsx
layout.jsx
```
In `src/app/layout.jsx`
```jsx
// object has to be 'metadata'
export const metadata = {
title: "Next.js",
description: "Generated by Next.js",
};
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
```
In `src/app/about/page.jsx`
```jsx
export const metadata = {
title: "About me",
};
export default function About() {
return <h1>About me</h1>;
}
```
all the routes will inherit the metadata of rootlayout page but the metadata inside their own page will take more precedence.
So for `localhost:3000/about` page title is 'About me' and descruption will be inherited by metadata object in `layout.jsx` in app folder.
**Dynamic metadata**
- Depends on dynamic info such as current route parameters, external data or metadata from parent segments
For dynamic routes, metadata may have to dynamic too. instead of exporting the object function is exported which returns the metadata with dynamic information
Structure
```text
src/app
products
[productId]
page.jsx
page.jsx
page.jsx
layout.jsx
````
In `src/app/products/[productId]/page.jsx`
```jsx
// function name has to be 'generateMetadata' case-sensitive
export const generateMetadata = ({ params }) => {
return {
title: `Product ${params.productId}`,
};
};
export default function ProductDetails({ params }) {
console.log("params: ", typeof params.productId);
return <h1> Details about Product {params.productId}</h1>;
}
```
As fetch can be used so this function ie generateMetadata can be async too
In `src/app/products/[productId]/page.jsx`
```jsx
// function name has to be 'generateMetadata' case-sensitive
export const generateMetadata = ({ params }) => {
return {
title: `Product ${params.productId}`,
};
};
export default function ProductDetails({ params }) {
console.log("params: ", typeof params.productId);
return <h1> Details about Product {params.productId}</h1>;
}
```
&nbsp;
**Title metadata**
- Title needed not be a string and it can be a object too. This object has 3 properties ie `absolute`, `default`, `template`.
- Default acts same as the one defined when title is string ie when inherited by other routes as when defined in layout.jsx
Structure
```text
src/app
blog
page.jsx
layout.jsx
```
In `src/app/layout.jsx`
```jsx
export const metadata = {
title: {
default: "Nextjs",
template: "%s | end",
},
description: "Generated by Next.js",
};
```
In `src/app/blog/page.jsx`
```jsx
export const metadata = {
title: {
default: "blog",
},
};
```
metadata of `localhost:3000/blog` is `blog | end`
If
```jsx
export const metadata = {
title: {
absolute: "blog",
},
};
```
then
metadata of `localhost:3000/blog` is `blog` as absolute will counter template too

View 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`.
&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>
</>
);
}
```

View file

@ -0,0 +1,160 @@
Coding 4
**Error Handling**
- To handle errors, another file is there named `error.jsx`.
- During development mode it will tell the detailed error ie where in the ocde there is error but in the production mode ie when we run `npm run build` then `npm run start` then we get different kind of error and to show specific message in that case
Structure
```text
src/app
products
[productId]
reviews
[reviewId]
error.jsx
page.jsx
page.jsx
```
In `src/app/products/[productId]/reviews/[reviewId]/page.jsx`
```jsx
import { notFound } from "next/navigation";
function getRandomInt(count) {
return Math.floor(Math.random() * count);
}
export default function ReviewDetail(prop) {
console.log("params: ", prop.params);
if (Number(prop.params.reviewId) > 1000) {
notFound();
}
if (getRandomInt(2) == 1) {
throw new Error("error with review");
}
return (
<h1>
Review {prop.params.reviewId} about product {prop.params.productId}
</h1>
);
}
```
So to catch these errors and display them
In `src/app/products/[productId]/reviews/[reviewId]/error.jsx`
```jsx
"use client";
export default function ErrorBoundary({ error }) {
return <div className="">Error in reviewId. Error is {error.message}</div>;
}
```
Make sure that error boundary is client component
- Automatically wrap a route segment and its nested children in a React Error Boundary
- Create error UI tailored to specific segments using the file-system heirarchy to adjust granularity
- Isolate errors to affected segments while keeping the rest of the application functional.
- Add functionality to attempt to recover from an error without a full page reload
&nbsp;
Component Heirarchy
```jsx
<Layout>
<Template>
<ErrorBoundary fallback={<Error />} >
<Suspense fallback={<Loading />}>
<ErrorBoundary fallback={<NotFound />} >
<Page />
</ErrorBoundary>
</Suspense>
</ErrorBoundary>
</Template>
</Layout>
```
&nbsp;
**Recovering from Errors**
- In props of ErrorBoundary there is a property named error through which we can print error. Also there is one more field ie reset which tries to reload the component giving error in case it get resolved.
- In order for the error to get resolved the component which was giving error must be client component too so use `use client;` at top in `page.jsx`.
In `src/app/products/[productId]/reviews/[reviewId]/error.jsx`
```jsx
"use client";
export default function ErrorBoundary({ error, reset }) {
return (
<div className="">
Error in reviewId. Error is {error.message} <br />
<button onClick={reset}>Try again</button>
</div>
);
}
```
&nbsp;
**Handling Errors in Nested Routes**
- Errors bubble up to the closest parent error boundary
- An error.jsx file will cater to errors for all its nested child segments
- By positioning error.jsx files at different levels in the nested folders of a route , we can achieve a more granular level of error handling.
Structure
```text
src/app
products
[productId]
reviews
[reviewId]
error.jsx
page.jsx
page.jsx
```
So here `error.jsx` is at `reviewsId` so layout.jsx at products folder so layout.jsx of products will render but for reviews folder , it wont as error bondary is for reviewsId so all the upper parents component will render.
If we shift the `error.jsx` to `products` then products `layout.jsx` wont execute too.
&nbsp;
**Handling errors in Layout**
- It is true that error.jsx file should be as close as to route as possible but unlike page.jsx layout component will render before error component so if error occurs in layout then error.jsx at same route/folder wont work.
- In such case error.jsx must be in parent folder for that route containing layout.jsx
Structure
```text
src/app
products
[productId]
layout.jsx
error.jsx
page.jsx
layout.jsx
```
In `src/app/products/[productId]/layout.jsx`
```jsx
"use client";
function getRandomInt(count) {
return Math.floor(Math.random() * count);
}
export default function ProductIdLayout({ children }) {
if (getRandomInt(2) == 1) {
throw new Error("error with review");
}
return (
<>
<h2>Features Products</h2>
{children}
</>
);
}
```
In `src/app/products/error.jsx`
```jsx
"use client";
export default function ErrorBoundary({ error, reset }) {
return (
<div className="">
Error in reviewId. Error is {error.message} <br />
<button onClick={reset}>Try again</button>
</div>
);
}
```

View file

@ -0,0 +1,306 @@
Coding 5 (Parallel Routes)
More advanced topics
# **Parallel Routes**
- Parallel routes are similar to using multiple React components in a layout.jsx file like this
Structure
```text
src/app
complex-dashboard
users.jsx
reviews.jsx
notifications.jsx
page.jsx
layout.jsx
components
card.jsx
```
In `src/app/complex-dashboard/layout.jsx`
```jsx
import Notifications from "./notifications";
import Reviews from "./reviews";
import Users from "./users";
export default function ComplexDashboardLayout({ children }) {
return (
<>
<div className="">{children}</div> {/* Contents from page.jsx */}
<div style={{ display: "flex" }}>
<div style={{ display: "flex", flexDirection: "column" }}>
<Users /> {/* Contents from users.jsx */}
<Reviews /> {/* Contents from reviews.jsx */}
</div>
<div style={{ display: "flex", flex: 1 }}>
<Notifications /> {/* Contents from notifications.jsx */}
</div>
</div>
</>
);
}
```
In `src/app/complex-dashboard/page.jsx`
```jsx
export default function ComplexDashboard() {
return <h1>Complex Dashboard</h1>;
}
```
In `src/app/complex-dashboard/users.jsx`
```jsx
import Card from "../components/card";
export default function Users() {
return <Card>Users</Card>;
}
```
Similarly in `reviews.jsx` and `notifications.jsx`
In `src/app/components/card.jsx`
```jsx
export default function Card({ children }) {
const cardStyle = {
padding: "100px",
margin: "10px",
boxShadow: "0 4px 8px 0 rgba(0,0,0,0.2)",
border: "1px solid #ddd",
display: "flex",
justifyContent: "center",
alignItems: "center",
};
return <div style={cardStyle}>{children}</div>;
}
```
&nbsp;
**Doing same with parallel routes**
- We have to use slots as they help structure our content in modular fashion
- We will use the '@folder_name' convention
- Each slot is passed as a prop to its corresponding 'layout.jsx' file
Transfer the files users.jsx, reviews.jsx and notifications.jsx like this
```bash
cd $projectRoot/src/app/complex-dashboard
mv users.jsx @users/page.js
mv reviews.jsx @reviews/page.js
mv notifications.jsx @notifications/page.js
```
Make sure that instead of 'page.jsx' 'page.js' should be used as that is expected from slots. Components may not rendered if `page.jsx` is used. Sometimes slot is not added in next so restart the dev server in such case.
Structure
```text
src/app
complex-dashboard
@users
page.js
@reviews
page.js
@notifications
page.js
page.jsx
layout.jsx
components
card.jsx
```
In `src/app/complex-dashboard/layout.jsx`
```jsx
export default function ComplexDashboardLayout({
children,
notifications,
users,
reviews,
}) {
console.log("users: ", users);
return (
<>
<div className="">{children}</div> {/* Contents from page.jsx */}
<div style={{ display: "flex" }}>
<div style={{ display: "flex", flexDirection: "column" }}>
{users} {/* Contents from users.jsx */}
{reviews} {/* Contents from reviews.jsx */}
</div>
<div style={{ display: "flex", flex: 1 }}>
{notifications} {/* Contents from notifications.jsx */}
</div>
</div>
</>
);
}
```
&nbsp;
Benefits of using parallel routes
- Ability to split a single layout into various slots, making the code more manageable though it is also possible with components
Coming to main benefits which is not possible with components
- Independent route handling
Unlike components, these slots can have their own loading and error states as they r handled like other routes without changing the url stack
This gives more control where different sections load at varying speeds or encounter unique errors.
![806ab46a3d11ebdd3d3d54109f75f173.png](../../../../_resources/806ab46a3d11ebdd3d3d54109f75f173.png)
- Sub navigation in routes
- Each slot can function as their own mini application with their own navigation and state management.
If we try to navigate to another route using components then it would be different as component is part of the page and when using `Link` component to change route then whole page has to be loaded so other component will not appear unless they r specifically rerendered in new page
![95bfea8e37d940bf5923d25fe037d8c4.png](../../../../_resources/95bfea8e37d940bf5923d25fe037d8c4.png)
&nbsp;
&nbsp;
# Unmatched Routes
- Adding a sub navigation in notifications slot
Structure
```text
src/app
complex-dashboard
@users
page.js
@reviews
page.js
@notifications
archived
page.jsx
page.js
page.jsx
layout.jsx
components
card.jsx
```
In `src/app/complex-dashboard/@notifications/archived/page.jsx`
```jsx
import Card from "@/app/components/card";
import Link from "next/link";
export default function Notifications() {
return (
<Card>
<div>Archived Notifications</div>
<Link href={"/complex-dashboard"}>Default</Link>
</Card>
);
}
```
In `src/app/complex-dashboard/@notifications/page.js`
```jsx
import Card from "@/app/components/card";
import Link from "next/link";
export default function Notifications() {
return (
<Card>
<div>Notifications</div>
<Link href={"/complex-dashboard/archived"}>Archived</Link>
</Card>
);
}
```
When user click on the link named 'Archived' then archived will be added in route so our route will change from `localhost:3000/complex-dashboard` to `localhost:3000/complex-dashboard/archived`.
- In layout.jsx there r 4 slots ie props.children, users, reviews and notifications. At `localhost:3000/complex-dashboard/archived` props.children, users, reviews are unmatched routes as archived folder is inside notifications slot.
- When navigating witin the UI and not adding `archived` directly with browser, nextjs retains the previously active state of a slot regardless of changes in the URL
- During page reload or directly typing archived in url we will get the error 404 if default.jsx is not found in corresponding unmatched slots. Even if one default.jsx is missing in any unmatched slot 404 error will there instead of other matched components getting loaded.
- Adding `default.jsx` in unmatched slot is neccessary as it serves as fallback to render contents when nextjs cannot retrieve a slot's active state from the current URL.
- We can define the UI for unmatched routes in any way in default.jsx and also mirror the content found in corresponding page.jsx.
Adding `default.jsx` in unmatched slots
```bash
# copying contents to default.jsx from page.jsx
cd $projectRoot/src/app/complex-dashboard
cp page.js default.js
cp @users/page.js @users/default.js
cp @reviews/page.js @reviews/default.js
```
Structure
```text
src/app
complex-dashboard
@users
default.js
page.js
@reviews
default.js
page.js
@notifications
archived
page.jsx
page.js
default.js
page.jsx
layout.jsx
components
card.jsx
```
&nbsp;
&nbsp;
# Conditional Routes
- With parallel routes it is possible to have conditional routes like login page or register page depending upon state and benefits with loading and error state and sub navigation unlike using component directly.
- Ternary operators can be used for conditional rendering
Structure
```text
src/app
complex-dashboard
@login.jsx
default.js
page.js
@users
default.js
page.js
@reviews
default.js
page.js
@notifications
archived
page.jsx
page.js
default.js
page.jsx
layout.jsx
components
card.jsx
```
In `src/app/complex-dashboard/@login/page.js` and `src/app/complex-dashboard/@login/default.js`
```jsx
import Card from "@/app/components/card";
export default function Login() {
return <Card>Please login to continue</Card>;
}
```
In `src/app/complex-dashboard/layout.jsx`
```jsx
export default function ComplexDashboardLayout({
children,
notifications,
users,
reviews,
login,
}) {
// if true that 'please login to continue' section wont appear
const isLoogedIn = false;
return isLoogedIn ? (
<>
<div className="">{children}</div> {/* Contents from page.jsx */}
<div style={{ display: "flex" }}>
<div style={{ display: "flex", flexDirection: "column" }}>
{users} {/* Contents from users.jsx */}
{reviews} {/* Contents from reviews.jsx */}
</div>
<div style={{ display: "flex", flex: 1 }}>
{notifications} {/* Contents from notifications.jsx */}
</div>
</div>
</>
) : (
login
);
}
```
Make sure that default.js file also exist which can be same as page.js for login slot

View file

@ -0,0 +1,139 @@
Coding 6(Intercepting Routes)
# Intercepting Routes
- Intercepting routes allow us to intercept or stop the default routing behaviour to present alternative view when navigating through UI, while still preserving the intended route
So it is useful when we wanna show a route while keeping context of current page
![a7d0a4ecdd2ac1a4b1c7fedd140f2c08.png](../../../../_resources/a7d0a4ecdd2ac1a4b1c7fedd140f2c08.png)
As we can see that when clicked on image, rest of page is blurred and that image is overlayed over others while keeping rest of page/images in background.
When page reloads or when we share the link to someone else the original image is shown and rest of page contents is lost.
&nbsp;
### Intercepting routes conventions
- (.) to match segments on the same level
Structure
```text
src/app
f1
(.)f2
page.jsx
f2
page.jsx
page.jsx
```
In `src/app/f1/page.jsx`
```jsx
import Link from "next/link";
export default function F1() {
return (
<>
<h1>F1 Page</h1>
<Link href={"/f1/f2"}>F2</Link>
</>
);
}
```
In `src/app/f1/f2/page.jsx`
```jsx
export default function F2() {
return (
<>
<h1>F2 Page</h1>
</>
);
}
```
In `src/app/f1/(.)f2/page.jsx`
```jsx
export default function F2() {
return (
<>
<h1>(.) Intercepted F2 Page</h1>
</>
);
}
```
- (..) to match segments one level above
```text
src/app
f1
(.)f2
page.jsx
f2
page.jsx
f3
page.jsx
f4
(..)f3
page.jsx
page.jsx
page.jsx
```
We can keep intercepted route of f3 inside folder f1 instead of inside f4 too and we wont need `(..)` too as `(.)` would suffice but when using lyout or template it is helpful to keep inside f4 rather inthan inside f1.
In `src/app/f1/f4`
```jsx
import Link from "next/link";
export default function F4() {
return (
<>
<h1>F4 Page</h1>
<Link href={"/f1/f3"}>F3</Link>
</>
);
}
```
Same for `src/app/f1/f3` and `src/app/f1/f4/(..f3)` with their respective page name
- (..)(..) to catch segments two level above. But this may have some issues
- (...) to match segments from the root app directory
Structure
```text
src/app
about
intro
page.jsx
f1
f4
page.jsx
(...)about
intro
page.jsx
```
In `src/app/f1/f4`
```jsx
import Link from "next/link";
export default function F4() {
return (
<>
<h1>F4 Page</h1>
<Link href={"/about/intro"}>Intro</Link>
</>
);
}
```
In `src/app/f1/f4/(...)about/intro/page.jsx`
```jsx
export default function Intro() {
return (
<>
<h1>(...) Intercepted Intro</h1>
</>
);
}
```
In `src/app/about/intro`
```jsx
export default function Intro() {
return <h1>Intro</h1>;
}
```

View file

@ -0,0 +1,408 @@
Coding 7(RESTful Route handlers)
- Unlike page routes, route handlers allow us to create RESTful endpoints, giving us full control over the response.
- We dont have to create and configure a separate server for that
- For making external API requests
- For securing private keys
In `src/app/flashboard/route.js`
```js
export async function GET() {
return new Response("flash board api data");
}
```
when visited to page `localhost:3000/flashboard` then it will represent this response
If there is page.jsx too like in `src/app/flashboard/page.js` then in this case page.jsx will take precedence over route.js and page.jsx content will be displayed. To avoid this make sure that page.jsx and route.jsx is never in same folder/route. So make sure to have different folder (say api) under flashboard folder and add route.jsx to that
```text
src/app
flashboard
api
route.jsx
page.jsx
```
&nbsp;
**GET Request**
in `src/app/comments/data.js`
```js
export const comments = [
{
id: 1,
text: "This is my first comment",
},
{
id: 2,
text: "This is my second comment",
},
{
id: 3,
text: "This is my third comment",
},
];
```
in `src/app/comments/route.js`
```js
import { comments } from "./data";
export async function GET() {
return Response.json(comments);
}
```
&nbsp;
**POST Request**
in `src/app/comments/route.js`
```js
export async function POST(request) {
const comment = await request.json();
const newcomment = {
id: comments.length + 1,
text: comment,
};
comments.push(newcomment);
return new Response(JSON.stringify(newcomment), {
headers: {
"Content-Type": "application/json",
},
status: 201,
});
}
```
Every POST route handler recieved a request in form of object
&nbsp;
**Dynamic Route Handler**
- for dynamic routes like `localhost:3000/comments/:id`
Structure
```text
src/app
comments
[id]
route.js
route.js
```
in `src/app/comments/[id]/route.js`
```js
import { comments } from "../data";
export async function GET(request, context) {
const { params } = context;
const comment = comments.find(
(comment) => comment.id === parseInt(params.id)
);
return Response.json(comments);
}
```
Here we have other parameter which is a object that contains params
&nbsp;
**Handling PATCH request**
in `src/app/comments/[id]/route.js`
```js
export async function PATCH(request, { params }) {
const body = await request.json();
const { text } = body;
console.log("text: ", text);
const index = comments.findIndex(
(comment) => comment.id === parseInt(params.id)
);
console.log("index : ", index);
comments[index]["text"] = text;
return Response.json(comments[index]);
}
```
&nbsp;
**Handling DELETE request**
in `src/app/comments/[id]/route.js`
```js
export async function DELETE(request, { params }) {
const index = comments.findIndex(
(comment) => comment.id === parseInt(params.id)
);
const deletedContext = comments[index];
comments.splice(index, 1);
return Response.json(deletedContext);
}
```
&nbsp;
**URL Query parameters**
- To handle and parse query parameters like `localhost:3001/comments?s=first`
we need to parameter in GET method.
- The paramater is of type NextRequest and contains nextUrl and this contains searchParams field too. searchParams field contains get method through which we can get values of query parameters
In `src/app/comments/route.js`
```js
export async function GET(request) {
const searchParams = request.nextUrl.searchParams;
const query = searchParams.get("s");
// if query is not null then only filter else print all comments
const filteredComments = query
? comments.filter((comment) => comment.text.includes(query))
: comments;
return Response.json(filteredComments);
}
```
&nbsp;
**Redirects in URL**
- Just like useRouter. useRouter is for client side and redirect is for server side.
to navigate to `/comments` in client side
```js
"use client";
import { useRouter } from "next/navigation";
const router = useRouter()
router.push('/comments')
```
to navigate `/comments` in server side
```js
import {redirect} from "next/navigation";
redirect('/comments');
```
In `src/app/comments/[id]/route.js`
```js
export async function GET(request, context) {
const { params } = context;
// if id is invalid then redirects
if (parseInt(params.id) > comments.length) {
redirect("/comments");
}
const comment = comments.find(
(comment) => comment.id === parseInt(params.id)
);
return Response.json(comment);
}
```
- When using this it sends status code as 307 which means for redirect
&nbsp;
**Headers in Route Handlers**
- HTTP headers represent the metadata associated with an API request and response
- Request Headers
- Sent by client to server containing info about request so server process it accordingly
- `User-Agent` indicates browser and OS
- `Accept` : indicates content-type that client will understand and expects server to send it in 'Content-Type' in response headers
- `Authorization` : fr authenticate itself to server. Eg : Bearer token
- Reponse Headers
- Sent by server to client containing info abour server and data sent in reponse
- `Content-Type` : indicates media type of response. eg : 'application/json', 'text/plain', 'text/html'.
- Headers Class can be used to create object after passing `req.headers` in its constructor
- there is a method named `headers` which can be imported from 'next/headers'
In `src/app/flashboard/api/route.js`
```js
import { headers } from "next/headers";
export async function GET(request) {
const reqHeaders = new Headers(request.headers);
const headerList = headers();
console.log(reqHeaders.get("Authorization"));
console.log(headerList.get("Authorization"));
return new Response("<h1> flash board api data </h1>", {
headers: {
// "Content-Type": "text/html",
"Content-Type": "text/plain",
},
});
}
```
&nbsp;
**Cookies in route handlers**
- Cookies are piece of data server sends of web browser
- Browser may store cookie and send it back to same server with later requests
- Purposes
- session management like logins and shopping carts
- Personalization like user preferences and themes
- Tracking like recording and anakyzing user behavior
- It can be defined by adding `Set-Cookie` field in headers and value if the form of `<name>=<value>`
- There r 2 ways. one is through standard way ie using `request.cookies.get('<cookie_name>')` and other is using cookies method from 'next/headers' module. this method will return an object which has get and set methods
In `src/app/flashboard/api/route.js`
```js
import { headers, cookies } from "next/headers";
export async function GET(request) {
const reqHeaders = new Headers(request.headers);
const headerList = headers();
cookies().set("resultsPerPage", "20");
const theme = request.cookies.get("theme");
const resultsPerPage = request.cookies.get("resultsPerPage");
console.log(reqHeaders.get("Authorization"));
console.log(headerList.get("Authorization"));
console.log(theme);
console.log("resultsperpage: ", cookies().get("resultsPerPage"));
// console.log(resultsPerPage);
return new Response("<h1> flash board api data </h1>", {
headers: {
// "Content-Type": "text/html",
"Content-Type": "text/plain",
"Set-Cookie": "theme=dark",
},
});
}
```
&nbsp;
**Caching in Route Handlers**
- Route Handlers are cached by default when using GET method with response object in Nextjs
In `src/app/time/route.js`
```js
export async function GET() {
const time = new Date().toLocaleTimeString();
return Response.json({ time });
}
```
In this one it will show try to cache the time so after the first request when we send this request `localhost:3000/time` result will be cached and will not be updated after furthur load
- How to opt out of caching
- dynamic mode in Segment Config Option
- using Request object with GET method
- employing dynamic functions like headers() and cookies()
- using any HTTP method other than GET
```js
// by default dynamic is 'auto'
export const dynamic = "force-dynamic";
export async function GET() {
const time = new Date().toLocaleTimeString();
return Response.json({ time });
}
```
&nbsp;
### Middleware
- Middleware in Next.js is powerful feature for intercepting and controlling flow of requests and responses within applications
- Does all of this at global level which significantly ehance feature like redirection, URL rewrites, authentication, headers and cookies management and more.
- Middleware allows to specify paths where it will be active
- Custom matcher config (like switch case)
- Conditional statements (if/else type)
In `src/middleware.js`
Custom matcher config
```js
import { NextResponse } from "next/server";
export function middleware(request) {
return NextResponse.redirect(new URL("/", request.url));
}
export const config = {
matcher: "/profile",
};
```
this will redirect every request whole path is `/profile` to `/`
- this redirection can be done in `profile` route itself but point of using middleware is change it without profile route is reached. Maybe that route has more code to be exeuted and we dont wanna temper with it so using middleware solved this issue or maybe that route dont exist or requires authentication
Conditional statements
```js
import { NextResponse } from "next/server";
export function middleware(request) {
if (request.nextUrl.pathname === "/profile") {
return NextResponse.redirect(new URL("/hello", request.url));
}
}
```
- rewrites : map a new path to an existing app component path without displaying URL changes to the user. it will route the traffic while masking original path. its limitation is that it cant route traffic to external domain
https://docs.digitalocean.com/products/app-platform/how-to/url-rewrites/
In `src/middleware.js`
```js
import { NextResponse } from "next/server";
export function middleware(request) {
if (request.nextUrl.pathname === "/profile") {
return NextResponse.rewrite(new URL("/hello", request.url));
}
}
```
so url will be displayed as `localhost:3000/profile` but content will be of `localhost:3000/hello`
- Cookies and Headers : Cookies and headers can also be added to middleware. Advantage is being setting them for global level for all routes
In `src/middleware.js`
```js
import { NextResponse } from "next/server";
export function middleware(request) {
// refers to next response in middleware chain as reponse is to be send to next middleware or route handler is
// current middleware is last one
const response = NextResponse.next();
const themePreference = request.cookies.get("theme");
if (!themePreference) {
response.cookies.set("theme", "dark");
}
response.headers.set("custom-header", "custom-value");
return response;
// if (request.nextUrl.pathname === "/profile") {
// return NextResponse.rewrite(new URL("/hello", request.url));
// }
}
```

View file

@ -0,0 +1,380 @@
Coding 8 (Rendering)
RSC in detail https://www.youtube.com/watch?v=X2eUQIjNxCQ
- Rendering is the rocess that transforms the code we write into user interfaces
- choosing right time and place for renering is key for performant application
- CSR (Client Side Rendering), SSR (Server Side Rendering), RSC(React Server Components)
### Rendering in React
- when client requests for web page it gets html + js file and html file is mostly blank and have link to js file
- **Client side rendering**
- Method of rendering where compoent code is transformed to user interface directly within the brower is known as client side rendering
- ![dda32c58411fd49ead491fe54ceaf0b5.png](../../../../_resources/dda32c58411fd49ead491fe54ceaf0b5.png)
- It became standard for SPAs(Single Page Apps)
- Drawbacks of CSR
- SEO : Generating HTML that mainly contains a single div tagis not optimal for SEO, as it provides little content for search engines to index
- Performance : Having browser handle all the work, fetcjing data, computing UI and making the HTML interactive can slow things down so users might see a blank screen or loading spinner while page loads
- Each new feature added to applicaton increases size of js bundle prolonging the wait time for users to see the UI and this delay is noticed by users with slow internet connection
- **Server side Rendering**(SSR)
- To overcome drawbacks of CSR, gatsby and next started to use SSR.
- ![0582a9e09684b83265f88c682b64d183.png](../../../../_resources/0582a9e09684b83265f88c682b64d183.png)
- Even though some problems related to SEO and performance was solved UI was still non interactive and for that Js reference is used
- Hydration
- Hydration is the process of attaching event listeners to the DOM, to make the static HTML interactive. Behind the scenes, hydration is done with the hydrateRoot
React API.
- When static html is served then react takes control in browser reconstructing component tree in memory
- It carefully plans the placement of interactive elements within this tree and react proceeds to bind necessary js logic to these elementsonalities required for a ully interactive iser experience
- This involves initializing application statem attaching event handlers for actions like click and mouseovers, setting up dynamic functionalities required for interactive User experience
- ![37fd67ae56fd0f4487e84586dc8630e2.png](../../../../_resources/37fd67ae56fd0f4487e84586dc8630e2.png)
- Server side solutions
1. Static Site Generation : When the application is deployed to the server which results in pages that are already rendered and ready to serve . It is ideal for content that doesnt change often like blog posts.
2. Server side rendering : Renders pages on demand in response to user requests . Sutable for personalized content where the HTML depends on the logged in user.
Server-Side Rendering was a significant improvement over CSR
- **Drawbacks of SSR** (All or Nothing waterfall)
1. You have to fetch everything before you can show anything
- Components cannot start rendering and then pause or wait while data is being loaded.
- If a component needs to fetch data from database or another source(like API) then fetching must be completed before the server can behin rendering the page
- This can delay server's response time to browser as server must finish collecting all necessary data before any part of page can be sent to client
2. We have to load everything before we can hydrate anything
- For successful hydration, where react adds interactivity to server rendered HTML, component tree must match exactly of server generated component tree
- This means all JS for components must be loaded on client befire we can start hydrating any of them
3. We have to hydrate everything before u can interact with anything
- As React hydrates component tree in single pass means all components must be hydrated before they can be interacted with any of them
4. Summary
- load data for entire page for viewing
- load js for entire page
- hydrate entire page
5. It is inefficient if some parts of app is slower than others as often with real world apps
&nbsp;
### Suspense SSR Architecture
- To combat all or nothing waterfall of SSR `<suspense>` component can be used which unlock 2 major SSR features
1. HTML streaming on the server
2. Selective hydration on the client
Rendering components without suspense
![76e14ea51e7166b22c55f3cd00ee55c3.png](../../../../_resources/76e14ea51e7166b22c55f3cd00ee55c3.png)
&nbsp;
**Rendering components with suspense**
![59186eb638f7630a7eb38bc5aa9a873a.png](../../../../_resources/59186eb638f7630a7eb38bc5aa9a873a.png)
- So html streaming will occur and once the server is ready for data for main section with inline script tag which contains minmal js to position that component so that it will be visible for ths user
This solve 2 problems ie
- No need to fetch everything before to show anything
- if particular section delays the initial html then it can seemlessly inthegrated to stream later.
- this is how it faciliates server side html streaming
Remaining challenges
- client side hydration cant start unless the js of main section is loaded
- and if the js bundle for the main section is large then it will delay process significantly
As html streaming section is solved but we also need to load js separtely for main section so other section can become interactive too and dont wait for main component
&nbsp;
**Code rendering**
- Code splitting allows us to mark specific code segments as not immediately necessary for loading, signalling your bundler to segregate them into separate `<scripts>` tags.
- Using `React.lazy` for code splitting enables you to separate the main section's code from primary js bindle
- The js containing React and the code for the entire application, excluding the main section can now be downloaded independently by the client without having to wait for main section's code.
for the following architecture
```text
src/app
about
Main.jsx
page.jsx
```
In `src/app/about/Page.jsx`
```js
"use client";
// function promiseSetTimeOut(time) {
// return new Promise((resolve, reject) => {
// setTimeout(() => {
// resolve();
// }, time);
// });
// }
function delayForDemo(promise) {
return new Promise((resolve) => {
setTimeout(resolve, 3000);
}).then(() => promise);
}
import { Suspense, lazy } from "react";
// Main component will be loaded 3s later
const Main = lazy(() => delayForDemo(import("./Main")));
export default function DashBoard() {
console.log("page loaded");
// const getDatainDelay = async (time, data) => {
// await promiseSetTimeOut(time);
// // return <button onClick={clickHandler}>data</button>;
// return <button>data</button>;
// };
return (
<>
<header>
<h1>Dashboard</h1>
</header>
<Suspense fallback={<button>Loading..</button>}>
{/* <main>{getDatainDelay(500, "hey this is main loaded")}</main> */}
<Main />
</Suspense>
<footer>copyright by nextjs</footer>
</>
);
}
```
In `src/app/about/Main.jsx`
```js
export default function Main() {
console.log("main loaded");
return <div className="Main">ghh</div>;
}
```
Selective hydration on the Client
- Wrapping the main section with `Suspense` rest of page will not be prevented from streaming and hydrating
- ![e39413e48b0043e492bc1dc3ee14600f.png](../../../../_resources/e39413e48b0043e492bc1dc3ee14600f.png)
&nbsp;
Drawbacks of Suspense SSR
- In react there is CSR so even if there is non interactive UI it will needs to undergo hydration
&nbsp;
## React Server Components (RSC)
- It is new architecture designed by React team
- The approach aims to leverage the strnegths of both server and client environments optimizing for efficiency
- It introduces a dual component model
- client components
- server components
- The distinction is not based on functionality of the components but rather on where they execute and specific environments they are designed to interact with.
&nbsp;
RSC and Next.js
- App router in Next.js is built on the RSC architecture
&nbsp;
### RSC Rendering Lifecycle
**RSC Loading Sequence**
![3d430e984fae82dde78badf4b729f50b.png](../../../../_resources/3d430e984fae82dde78badf4b729f50b.png)
https://nextjs.org/docs/app/building-your-application/rendering/client-components
- Browser sends request to the server about route.
- Nextjs recieves the request and match server component(SC) respective for the route
- Nextjs instructs react to render server component
- React render the server component and any child component that r part of server component converting them to RSC payload.
If any of server component suspends then react pauses rendering of subtree (child components along with it) and sends a placeholder value instead meanwhile client components are prepared with instructions for later in the life cycle.
- This RSC payload is used by next which contains client component instruction to generate HTML for both components(client and server) on the server for the route
- Generated html is streamed to the client along with RSC payload which reconcile the client and server components in order to update the DOM ie progressively render UI. this checking/matching of server and client component trees (ensures that the client-side representation of a component matches the server-side-rendered HTML that was initially sent to the browser. ) is important for maintaining consistency.
- Finally hydration happens which converts it into interactive UI by attaching event listeners
&nbsp;
**RSC Update Sequence**
Related to refresing parts of the app
![f260be10c48c6fd437878a1074e7bb3a.png](../../../../_resources/f260be10c48c6fd437878a1074e7bb3a.png)
- Browser requests refetch of specic UI such as a full route.
- Next matches SC component and instruct react to render server component and react render components like the initial loading step.
- Unlike initial loading there is no HTML generation and this RSC payload is progressively streamed back to client
- On recieving route is re rendered using this RSC payload which is then reconiled and merged with new rendered output with existing component on screen.
- This UI description is in JSON format and not HTML, react can update DOM while preserving crucial UI updates such as focus or input values.
&nbsp;
## Server rendering Strategies
- Static rendering
- Dynamic rendering
- Streaming
&nbsp;
### Static rendering
- Generate HTML pages at time of building our applications. Means all data and content of web page is prepared in advanced.
- This approach means results can be cached by CDN and served to client instantly
- Able to share the rendered work to different users resulting in significant performace boost for application
- Useful for blogs, e-commerce product pages, documentation and marketing pages
&nbsp;
**How to Statically Render?**
- It is default rendering strategy in the app router and all routes are automatically prepared at build time without additional setup
&nbsp;
Production vs Dev Server
- For production,an optimized build is created once
- In development it is inefficient to build app after every changes
- in production builds, page is pre-rendered once build command is run
- in development mode, page will be pre-rendered for every request.
.next folder
- when building this is the output we get this
![6ab5db7b6fde89f907e0509a40c873d9.png](../../../../_resources/6ab5db7b6fde89f907e0509a40c873d9.png)
- The size is the amount of assets downloaded to perform a client-side transition to that page (after you've paid the "first load" for a different page). Means when we go from page A to B then the assets required which is basically difference as for navigating not all the assets is required as most of them r initially loaded
- First Load JS is the total amount of assets your users will download when visiting the page from the server instead of navigating as initially nothing is loaded.
- First load js is the important metric for performance
https://github.com/vercel/next.js/pull/12034
https://github.com/vercel/next.js/issues/10565
`.rsc` files
- these are the compact string representation of virtual DOM and includes abbreviations, internal references and encoded special meanings
- for the server components these `.rsc` files contain text which is displayed on web page too. Means it include rendered result of server component
![cc82dca645b175b114ebd8e370002060.png](../../../../_resources/cc82dca645b175b114ebd8e370002060.png)
- for the client components it contains placeholders/instructions instead means a refernce to chunks js file.
![b07c69aa4466bb2fc84630297b41983a.png](../../../../_resources/b07c69aa4466bb2fc84630297b41983a.png)
- This chunk js file referened by client component rsc is necessary for reconcilation and hydration
&nbsp;
**Prefetching**
- Prefetching is a technique used to preload a route in the background before the user navigates to it
- Routes are fetched automatically as they become visible in user's viewport when page first loads or it comes to view through scrolling
- For static routes, entire route is prefetched and catched by default.
- When homepage is loaded, nextjs prefetches the route whose links are there in homepage means `Link` components with those routes
&nbsp;
### Dynamic rendering
- It is server rendering strategy where routes are rendered separately for each user at a request time
- Useful when a route has personalized data or cookies info or url search params that can only be known at request time.
- News website, personalized e-commerce pages and social media feeds
&nbsp;
**How to dynamically render**
- During rendering, if dynmaic function is discovered then nextjs will switch to dynmaic rendering for whole route
- In nextjs fynmaic functions are `cookies()`, `headers()` and `searchParams` and using any of these will switch to dynamic rendering at request time for the route.
Structure
```text
src/app
static
page.jsx
about
page.jsx
layout.jsx
page.jsx
```
In `src/app/static/page.jsx`
```js
import { cookies } from "next/headers";
export default function Static() {
// to force dynamaic rendering
const cookieStore = cookies();
const theme = cookieStore.get("theme");
console.log("theme: ", theme);
return (
<div className="Static">
<h1>Static</h1>
</div>
);
}
```
- After building we get this output in terminal
![7c2152bc0ec8f03902aded1280ca0afc.png](../../../../_resources/7c2152bc0ec8f03902aded1280ca0afc.png)
This `/static` route will be dynmiacally rendered means it will not be rendered on build but rendered on nodejs when request is made
Also in `.next` there will be no `static.html` like about and root route have
&nbsp;
### Streaming
- Streaming is a strategy for allowing for progressive UI rendering from the server.
- Work is divided into chunks and streamed to client as soon its ready
- Enables users to get intitial look immediately and wait for whole page to load progressively
- Streaming is integrated into nexjs app router by default
```text
src/app
product-detail
page.jsx
components
product.jsx
reviews.jsx
layout.jsx
page.jsx
```
In `src/app/components/product.jsx`
```js
const DELAYTIME = 2000;
export async function Product() {
await new Promise((resolve) => setTimeout(resolve, DELAYTIME));
return <div>Product</div>;
}
```
In `src/app/components/reviews.jsx`
```js
const DELAYTIME = 4000;
export async function Reviews() {
await new Promise((resolve) => setTimeout(resolve, DELAYTIME));
return <div>Reviews</div>;
}
```
In `src/app/product-detail/page.jsx`
Without using suspense
```js
import { Product } from "../components/product";
import { Reviews } from "../components/reviews";
export default function ProductDetail() {
return (
<div>
<h1>Product Detail Page</h1>
<Product />
<Reviews />
</div>
);
}
```
The page will take 4s to load bcz the reviews page is taking that much time and page will only load once all the component is rendered.
So to have a fallback till those components are loaded so that user can see the page atleast use suspense
With suspense
```js
import { Suspense } from "react";
import { Product } from "../components/product";
import { Reviews } from "../components/reviews";
export default function ProductDetail() {
return (
<div>
<h1>Product Detail Page</h1>
<Suspense fallback={<p>Loading Product...</p>}>
<Product />
</Suspense>
<Suspense fallback={<p>Loading Reviews...</p>}>
<Reviews />
</Suspense>
</div>
);
}
```

View file

@ -0,0 +1,508 @@
Coding 9 (Composition Patterns)
Server Components
- Fetching data
- Directly accessing backend resources
- Protecting sensitive information (like access tokens and API keys) on the server
- Keeping large dependencies server-side helping in reducing client side javascript
&nbsp;
Client Components
- Adding interactivity and handling event listeners
- Managing state and lifecycle effects ( useState(), useReducer(), useEffect() )
- Using browser-exclusive APIs
- Custom hooks
- React Class components
&nbsp;
## Server-only code
- Its not wise to include server side code to prevent exposing logic, api keys or data also it may not work on client too
- So its important to have a clear boundary
- Create server side functions in different files and import `server-only` module in that file(containing server side function) which will give error at build time if its code is used in client components
```text
src/app
utils
server-utils.jsx
server-route
page.jsx
client-route
page.jsx
```
In `src/app/utils/server-utils.jsx`
```js
import "server-only";
export const ServerSideFunction = () => {
console.log(
`use multiple libraries,
use environment variables,
interact with a database,
process confidential information`
);
return "server result";
};
```
In `src/app/server-route/page.jsx`
```js
import { ServerSideFunction } from "../utils/server-utils";
export default function ServerRoutePage() {
console.log("Server router rendered");
const result = ServerSideFunction();
return (
<>
<h1>ServerRoutePage</h1>
<p>{result}</p>
</>
);
}
```
In `src/app/client-route/page.jsx`
```js
"use client";
import { ServerSideFunction } from "../utils/server-utils";
export default function ClientRoutePage() {
console.log("Client route rendered");
const result = ServerSideFunction();
return (
<>
<h1>ClientRoutePage</h1>
<p>{result}</p>
</>
);
}
```
&nbsp;
**Third Party Packages**
- third party packages in npm dont use 'use client' directive so they cant be used in server components so we need to encapsulate them in another client component and use it instead
- It is possible to use nested client side component inside server side component
Example : Using `react-slick` package
Structure
```text
src/app
components
ImageSlider.jsx
ImageSlider.css
utils
server-utils.jsx
server-route
page.jsx
client-route
page.jsx
```
In `src/app/components/ImageSlider.jsx`
```js
"use client";
// import { ServerSideFunction } from "../utils/server-utils";
import Slider from "react-slick";
// Import css files
import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css";
import "./ImageSlider.css";
export default function ImageSlider() {
console.log("Client route rendered");
// const result = ServerSideFunction();
var settings = {
dots: true,
infinite: true,
speed: 500,
slidesToShow: 1,
slidesToScroll: 1,
};
return (
// <>
// <h1>ClientRoutePage</h1>
// <p>{result}</p>
// </>
// <Slider {...settings}>
<Slider {...settings}>
<div className="fit-con">
<img src="https://picsum.photos/id/34/367/267" alt="picsum" />
</div>
<div className="fit-con">
<img src="https://picsum.photos/id/35/367/267" alt="picsum" />
</div>
<div className="fit-con">
<img src="https://picsum.photos/id/37/367/267" alt="picsum" />
</div>
<div className="fit-con">
<img src="https://picsum.photos/id/41/367/267" alt="picsum" />
</div>
<div className="fit-con">
<img src="https://picsum.photos/id/40/367/267" alt="picsum" />
</div>
<div className="fit-con">
{/* <img src="https://picsum.photos/id/39/367/267" alt="picsum" /> */}
<h1>6</h1>
</div>
</Slider>
);
}
```
In `src/app/components/ImageSlider.css`
```css
.fit-con {
display: flex !important;
justify-content: center;
}
```
In `src/app/server-route/page.jsx`
```js
import ImageSlider from "../components/ImageSlider";
import { ServerSideFunction } from "../utils/server-utils";
export default function ServerRoutePage() {
console.log("Server router rendered");
const result = ServerSideFunction();
return (
<>
<h1>ServerRoutePage</h1>
<p>{result}</p>
<div style={{ width: "367px", margin: "auto" }}>
<ImageSlider />
</div>
</>
);
}
```
**Context Providers**
- Context providers are typically rendered near the root of an application to share global application state and logic. Eg : App theme
- React context is not supported in Server Compinent so just like encapusalating third package in separate client component we need to do same for this
Structure
```text
src/app
layout.jsx
client-route
page.jsx
components
theme-provider.jsx
```
In `src/app/components/theme-provider.jsx`
```js
"use client";
import { createContext, useContext } from "react";
const defaultTheme = {
colors: {
primary: "#007bff",
secondary: "#6c757d",
},
};
const ThemeContext = createContext(defaultTheme);
export const ThemeProvider = ({ children }) => {
return (
<ThemeContext.Provider value={defaultTheme}>
{children}
</ThemeContext.Provider>
);
};
export const useTheme = () => useContext(ThemeContext);
export { ThemeContext };
```
In `src/app/layout.jsx`
```js
import { Inter } from "next/font/google";
import { ThemeProvider } from "./components/theme-provider";
export const metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({ children }) {
return (
<html lang="en">
<ThemeProvider>
<body>{children}</body>
</ThemeProvider>
</html>
);
}
```
In `src/app/client-route/page.jsx`
```js
"use client";
import { useContext } from "react";
import { ThemeContext } from "../components/theme-provider";
export default function ClientRoutePage() {
const theme = useContext(ThemeContext);
return (
<h1
style={{
color: theme.colors.secondary,
}}
>
Client Route
</h1>
);
}
```
To update the context value, use useState and transfer state, stateChanger t value of context provider
```js
import ReactDOM from "react-dom";
import React, { useState } from "react";
import authContext from "./authContext";
import Login from "./Login";
const App = () => {
const [authenticated, setAuthenticated] = useState(false);
return (
<authContext.Provider value={{ authenticated, setAuthenticated }}>
<div> user is {`${authenticated ? "" : "not"} authenticated`} </div>
<Login />
</authContext.Provider>
);
};
ReactDOM.render(<App />, document.getElementById("container"));
```
&nbsp;
## Client-only Code
- To prevent unintended server side usage of client code we can install and import package `client-only`
&nbsp;
Client Component Placement
- It is recommended to position client components lower in the component tree
- Once the component is client component all the child component becomes client components too
```text
src/app
components
navbar.jsx
navlink.jsx
navsearch.jsx
landing-page
page.jsx
```
In components
```js
// navlink.jsx
export default function Navlink() {
console.log("Navlink loaded");
return <div className="Main">NavLink</div>;
}
//navsearch.jsx
"use client";
import { useState } from "react";
export default function NavSearch() {
const [search, setSearch] = useState("");
console.log("NavSearch loaded2");
return <div className="Main">NavSearch</div>;
}
//navbar.jsx
import Navlink from "./navlink";
import NavSearch from "./navsearch";
export default function NavBar() {
console.log("navbar loaded");
return (
<>
<div className="">NavBar</div>
<Navlink />
<NavSearch />
</>
);
}
```
- useState hook can be used in navbar too but since its usage is required only in navsearch file so its best to use it there otherwise navbar needs to be a client component and navlink will be client component too
In `src/app/landing-page.jsx`
```js
import NavBar from "../components/navbar";
export default function LandingPage() {
return (
<div className="">
<h1>Landing Page</h1>
<NavBar />
</div>
);
}
```
&nbsp;
**Interleaving Server and Client components**
- Server component cannot be directly used inside client component as they are automatically converted to client component by default
- So a workaround is needed for this ie passing server component as prop to client component
```text
src/app
interleaving
page.jsx
components
client-component.jsx
server-component.jsx
```
In `src/app/server-component.jsx`
```js
import fs from "fs";
export default function ServerComponent() {
console.log("ServerComponent loaded");
const fileBuffer = fs.readFileSync("package.json");
return (
<div className="ServerComponent">
<h1>Server Component</h1>
</div>
);
}
```
Following wont work and will give error that fs is not working as server component which is children of client component becomes client component
In `src/app/interleaving.jsx`
```js
import ClientComponent from "../components/client-component";
export default function InterleavingPage() {
console.log("InterleavingPage loaded");
return (
<div className="InterleavingPage">
<ClientComponent />
</div>
);
}
```
In `src/app/client-component.jsx`
```js
"use client";
import { useState } from "react";
import ServerComponent from "./server-component";
export default function ClientComponent() {
console.log("client component loaded");
const [state, seyState] = useState();
return (
<div className="client-component">
<h1>Client Component</h1>
<ServerComponent />
</div>
);
}
```
Passing server component as props instead
In `src/app/interleaving.jsx`
```js
import ClientComponent from "../components/client-component";
import ServerComponent from "../components/server-component";
export default function InterleavingPage() {
console.log("InterleavingPage loaded");
return (
<div className="InterleavingPage">
<ClientComponent>
<ServerComponent />
</ClientComponent>
</div>
);
}
```
In `src/app/client-component.jsx`
```js
"use client";
import { useState } from "react";
// import ServerComponent from "./server-component";
export default function ClientComponent({ children }) {
console.log("client component loaded");
const [state, seyState] = useState();
return (
<div className="client-component">
<h1>Client Component</h1>
{children}
{/* <ServerComponent /> */}
</div>
);
}
```

View file

@ -0,0 +1,252 @@
Coding
**Routes**
- Create another folder in app folder named 'about'. In about create a file named page.jsx and type following
```js
export default function About() {
return <h1>About me</h1>;
}
```
- Do same with 'Profile'
```js
export default function Profile() {
return <h1>Profile</h1>;
}
```
File Structure is
```text
src/app
about
page.jsx
profile
page.jsx
page.jsx
layout.jsx
````
&nbsp;
**Nested Routes**
- means more folders say (first and second in blog folder and blog in app folder)
Structure
```text
src/app
blog
first
page.jsx
second
page.jsx
page.jsx
layout.jsx
````
&nbsp;
**Dynamic routes**
- pages with custom params in url
Structure
```text
src/app
products
[productId]
page.jsx
page.jsx
page.jsx
layout.jsx
````
`src/app/products/page.jsx`
```js
export default function ProductDetails() {
return <h1> Details about Product</h1>;
}
```
`src/app/products/[productId]/page.jsx`
```jsx
export default function ProductDetails({ params }) {
return <h1> Details about Product {params.productId}</h1>;
}
```
or if its typescript then
```tsx
export default function ProductDetails({ params } :
{params: {productId: string};
}) {
return <h1> Details about Product {params.productId}</h1>;
}
```
Each function contains parameter object which has property params. This params is also object which contain property productId which is of type string
&nbsp;
**Nested Dynamic routes**
Structure
```text
src/app
products
[productId]
reviews
[reviewsId]
page.jsx
page.jsx
page.jsx
page.jsx
layout.jsx
````
In `src/app/products/[productId]/reviews/[reviewId]/page.jsx`
```jsx
export default function ReviewDetail(prop) {
return (
<h1>
Review {prop.params.reviewId} about product {prop.params.productId}
</h1>
);
}
```
Here prop will contain params, params will contain 2 fiels ie productId and reviewId and these both r strings. in `localhost:3000/products/1/reviews/2` output is
`params: { productId: '1', reviewId: '2' }`
&nbsp;
**Catching Segments**
- Even with nested dynamic routes we may not know what type of routes or how much nesting is needed bcz page may contain dynamic links so to solve it catching such segments is required.
Structure
```text
src/app
docs
[...slug]
page.jsx
page.jsx
layout.jsx
````
In `src/app/docs/[...slug]/page.jsx`
```jsx
export default function Slug({ params }) {
console.log("params: ", params);
if (params.slug.length === 1) {
return <h1>only 1 {params.slug[0]}</h1>;
} else if (params.slug.length === 2) {
return (
<h1>
only 2 {params.slug[0]} and {params.slug[1]}
</h1>
);
}
return <h1> no one :( </h1>;
}
```
here params is object which will contain field named slug which is array of strings and contain all params after that. so if url `localhost:3000/docs/doc1/rev/rev1` then slug will be `['doc1', 'rev','rev1']`
the route `[...slug]` will only be visited if there r params after docs. To make sure that `page.jsx` works too then we need to use optional catch all. to do that enclose `[...slug]` with one more square bracket like this `[[...slug]]`. and at `localhost:3000/docs` `no one` will be showed.
Optional catch all
In `src/app/docs/[[...slug]]/page.jsx`
```jsx
export default function Slug({ params }) {
console.log("params: ", params);
if (params.slug?.length === 1) {
return <h1>only 1 {params.slug[0]}</h1>;
} else if (params.slug?.length === 2) {
return (
<h1>
only 2 {params.slug[0]} and {params.slug[1]}
</h1>
);
}
return <h1>no one :(</h1>;
}
```
&nbsp;
**Custom Not-Found**
- By default when we visit a route which is not configured then error message is displayed of nextjs default configuration. So for custom one
Create file named `not-found.jsx` in app folder
In `src/app/not-found.jsx`
```jsx
export default function NotFound() {
return (
<div className="">
<h2>Page not found</h2>
<p>Not able to find requested resource</p>
</div>
);
}
```
so for unconfigured url this page will be displayed
In dynamic routes, params can be checked using if and if edge condition for error pass then this page can be displayed
```jsx
// importing notFound from 'next/navigation'
import { notFound } from "next/navigation";
export default function ReviewDetail(prop) {
console.log("params: ", prop.params);
if (Number(prop.params.reviewId) > 1000) {
notFound();
}
return (
<h1>
Review {prop.params.reviewId} about product {prop.params.productId}
</h1>
);
}
```
As `not-found.jsx` is in app folder so all folders under this will inherit this not-found page. So if we wanna have custom one according to folder then create `not-found.jsx` for specific folder
So in `src/app/products/[productId]/reviews/[reviewId]/page.jsx`
```jsx
export default function notfoundRev() {
return <h1>Review not found</h1>;
}
```
So now this page will be displayed
&nbsp;
**File Collocation**
- `page.jsx` is important as it acts like a index.html for html css project, main() function in java or C. So next will try to find this file inside the folder and there must be one function which must be exported as default using `export default`.
In `src/app/dashboard/line-chart.jsx`
```jsx
export default function LineChart() {
return <h1>Line Chart</h1>;
}
```
In `src/app/dashboard/page.jsx`
```jsx
import LineChart from "./line-chart";
function BarChart() {
return <h1>Bar Chart</h1>;
}
function DashBoard() {
return <h1>Dashboard</h1>;
}
export default function Main() {
return (
<div className="">
<LineChart />
<BarChart />
<DashBoard />
</div>
);
}
```

View file

@ -0,0 +1,41 @@
- nextjs alternative : remix
Initialization
https://yewtu.be/watch?v=__mSgDEOyv8
- Use this to setup nextjs
`npx create-next-app@latest myapp`
Then `npm run dev` to run it
- To run a production build
`npm run build` then
`npm run start`
- Running on different port
In `package.json`
```json
"scripts": {
"dev": "next dev -p 3001",
"build": "next build",
"start": "next start -p 3001",
"lint": "next lint"
},
```
- running it as serverless mode, generate SSG
in next.config.js, do following for static export
```js
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
output: 'export',
// Optional: Change links `/me` -> `/me/` and emit `/me.html` -> `/me/index.html`
// trailingSlash: true,
// Optional: Prevent automatic `/me` -> `/me/`, instead preserve `href`
// skipTrailingSlashRedirect: true,
// Optional: Change the output directory `out` -> `dist`
// distDir: 'dist',
}
module.exports = nextConfig
```

View file

@ -0,0 +1,55 @@
Theory
https://www.youtube.com/watch?v=r8nXMA_pf0w : importance of nextjs
https://nextjs-doc.surge.sh/docs/next/Theory
- Uses react to building user interfaces
- Extra features are routing, optimized rendering, data fetching, bundling , compiling and more
Why Learn nextjs
1. **Routing**: file based routing so no need to install third party routng packages and configure it.
2. **API Routes**: api supports a nextjs is full stack framework
3. **Rendering** : both client and server side rendering.
4. Styling : Supports css modules, tailwind css
5. Optimization : optimization for images, fonts and scripts
### Project Structure
- package.json : contains dependencies and scripts
- next.config.js : for nextjs
&nbsp;
**Folders**
- .next : this folder generated when we run dev or build scripts and using this we get output. its included in `.gitignore`
- public :holds static assets to be served like images and SVGs
- src : most important folder. It contains app folder inside it by default which is also called app router. Inside it, there r some files.
- globals.css : like index.css in react
- layout.js : like index.js
- page.js : like App.js
- Flow of control
package.json -> layout.js -> page.js -> browser
&nbsp;
**React Server Components**
1. Server Components
- Default component
- Ability to run task like reading file or fetching data from data base.
- They cant use hooks or handle user interaction.
2. Client Components
- To create a Client Component, add `use client` at top of component file
- They cant read files but can use hooks and manage user interaction
&nbsp;
**Routing**
- It has file file system based routing
- URL paths which user can access in browser are defined by files and folders in your codebase
&nbsp;
**Framwork Conventions**
1. Routes in the app folder
2. Every file corresponding to the routes must be placed inside the page.jsx or page.tsx
3. Every folder corresponds to a path segment in the browser URL.
It has convention over configuration process for routing

View file

@ -0,0 +1,45 @@
Tips
- To import anything relative to src directory use `@` like following code
Structure
```text
src
app
page.jsx
components
card.jsx
```
In `src/app/page.jsx`
```jsx
import Card from '@/components/card'
export default function App(){
<>
<Card>Tools</Card>
</>
}
```
In `src/components/card`
```jsx
export default function Card({ children }) {
const cardStyle = {
padding: "100px",
margin: "10px",
boxShadow: "0 4px 8px 0 rgba(0,0,0,0.2)",
border: "1px solid #ddd",
display: "flex",
justifyContent: "center",
alignItems: "center",
};
return <div style={cardStyle}>{children}</div>;
}
```
- multiple root layouts
https://www.youtube.com/watch?v=X9_XqeqWBR0
&nbsp;
Route grouping will be used so remove layout,jsx from root and instead use them in route group folders. Multiple layouts at same root is possible but not multiple pages so at whichever route there is page.jsx that will be considered as default route
Next.js App Router Multiple Root Layouts: Explained With Examples.mp4
https://files.catbox.moe/eiy18h.mp4