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

7.9 KiB

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
src/app
	blog
		page.jsx
	products
		page.jsx
	page.jsx

In src/app/page.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

import Link from "next/link";

export default function Blog() {
  return (
    <>
      <h1>Blog</h1>
      <Link href="/">Home</Link>
    </>
  );
}

For Dynamic Routes Structure

src/app
	blog
		page.jsx
	products
		[productId]
			page.jsx
		page.jsx
	page.jsx

In src/app/products/page.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
src/app
	(auth)
		login
		password
		forgot-password
		layout.jsx
	page.jsx

In src/app/(auth)/layout.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
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

"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

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
src/app
	order-product
		page.jsx
	page.jsx

In src/app/order-product/page.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
src/app
	(auth)
		login
		password
		forgot-password
		layout.jsx
		style.css
	page.jsx

In src/app/(auth)/layout.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

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
src/app
	blog
		first
		second
		loading.jsx
		layout.jsx
		page.jsx
	page.jsx

In src/app/blog/loading.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

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>
    </>
  );
}