Skip to content

Web Development - Nextjs

API Calling in the Client Side (App Router)


Use fetch() to call APIs written in the App Router directly from client components.

Pre-requisite API must be defined under the following structure: app/ ├── api/ │ └── apiName/ │ └── route.ts

Basic Syntax

  • In Asynchronous
await fetch('api/apiName')
  • In synchronous
fetch('api/apiName')

Note:

  • Asynchronous calls are recommended for data fetching in client components for smooth user experience.

Common Use Cases

Call a contact API (from src/app/api/contactApi/route.ts) without parameters on component mount

useEffect(() =>{
async function fnFetchContact(){
const LdContact = await fetch('api/contactApi') //call the contactApi
const LdResult = await LdContact.json()
console.log(LdResult)
}
fnFetchContact()
},[])

Sample Output

{
data: {"name": "John Doe", "email": "john@example.com"},
message: "contact created Successfully
}

Call a Contact API with parameters (e.g., email) on component mount

useEffect(() =>{
async function fnFetchContact(){
//passing the Email id(xyz@example.com)
const LdContact = await fetch(`api/contactApi?email=${Email}`)
const LdResult = await LdContact.json()
console.log(LdResult)
}
fnFetchContact()
},[])

Sample Output

{data: {"name": "John Doe", "email": "xyz@example.com"},
message: "contact created Successfully
}

Get the Dynamic route segment in client component


Use useParams() to access dynamic segments of the current URL in the client component. Ex: folder structure of the nextjs app

app/
├── [locale]/
│ └── products/
│ └── [slug]/
│ └── page.tsx

Basic Syntax

const LdParam = useParam()

Common Use Cases Note: you can access n number of dynamic segments based on the name you have provided like we did ([locale], [slug])

//to get the current locale(langauage)
console.log("language:",LdParam.locale)
//to get the current product name i.e slug id
console.log("slug:", LdParam.slug)

Sample Output on browser, Visit “https:///en/products/lens-erp-suite”

language:"en"
slug:"lens-erp-suite"

Conditional Rendering: Logical AND (&&) and Ternary Operator


Helps you show/hide content based on props, state, route params, session status, etc.

Using && (logical AND)

{condition && <Component />}

Using Ternary Operator

{condition ? <ComponentIfTrue /> : <ComponentIfFalse />}
OptionsDescription
&& (AND)Renders the component only if condition is true
? : (ternary)Renders one of two components based on condition

Common Use Case: Displaying message based on user login status

'use client'
import { useState } from 'react'
export default function Page() {
const [loggedIn, setLoggedIn] = useState(false)
return (
<div>
{loggedIn ? <p>Welcome back!</p> : <p>Please log in!</p>}
</div>
)
}

Sample Output:

Output when loggedIn = true:

Welcome back!

Output when loggedIn = false:

Please log in!

generateMetadata()


Used to dynamically set page metadata like title, description, and social tags for better SEO and sharing.

Basic Syntax:

export async function generateMetadata() {
return {
title: 'Your Page Title',
description: 'Your Page Description',
// Optional: Add more fields like openGraph, twitter, etc.
}
}
parametersDescription
paramsContains dynamic route values (e.g., from [slug] or [id])
searchParamsContains query parameters (e.g., ?sort=asc)

Common Use Case: Sets the page metadata dynamically based on the blog post slug: If the path is:app/blog/[slug]/page.js and you visit the URL: blog/my-first-post then params.slug = 'my-first-post'

export async function generateMetadata({ params }) {
const post = await fetchPostBySlug(params.slug)
return {
title: post.title,
description: post.excerpt,
}
}

Sample Output : If the fetched post is:

{
"title": "My First Post",
"excerpt": "This is a summary of my first post."
}

Then the page <head> includes:

<head>
<title>My First Post</title>
<meta name="description" content="This is a summary of my first post." />
</head>

Note:

  • You can define metadata in both layout.js and page.js.
  • Next.js automatically injects metadata into the page’s <head>.
  • generateMetadata() is server-side only (works only in Server Components).

generateViewport()


Used to dynamically set the <meta name="viewport"> tag, which controls how your site is displayed on different screen sizes and devices.

Basic Syntax:

import type { Viewport } from 'next'
export const viewport: Viewport = {
//viewport fields
}

Viewport Fields

PropertyTypeDescription
widthstringSets the viewport width (e.g 'device-width', '1024')
heightstringViewport height (not widely supported) (e.g 'device-height', '768') (Rare)
initialScalenumberZoom level when the page loads (e.g 1, 0.75, 1.5)
minimumScalenumberMinimum zoom level (e.g 0.1 to 10)
maximumScalenumberMaximum zoom level (e.g 0.1 to 10)
userScalablebooleanWhether zooming is allowed (true or false)
viewportFitstringControls layout for devices with notches (e.g 'auto', 'contain', 'cover')
themeColorstringSets browser UI theme color, affecting mobile address bar (e.g '#ffffff', 'transparent')

Common Use Case: Set a standard responsive viewport for mobile devices:

import type { Viewport } from 'next'
export const viewport: Viewport = {
width: 'device-width',
initialScale: 1,
maximumScale: 1,
userScalable: false,
}

Sample Output :

The page <head> includes:

<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
/>

Note:

  • You can define it inside layout.js or page.js depending on whether you want a global or per-page viewport configuration.
  • generateViewport() is server-side only (works only in Server Components).

useState()


Used to add state management to functional React components, allowing components to hold and update local state.

useState works only on the client side so be sure to add "use client"; directive at the top of your component file.

Basic Syntax:

"use client";
import { useState } from 'react';
const [state, setState] = useState(initialValue);
ParameterDescription
stateThe current value of your state variable
setStateFunction to update the state variable
initialValueThe initial value assigned to the state variable

Common Use Case: Create a counter that increments when a button is clicked:

"use client";
import React, { useState } from 'react'
function Counter() {
const [count, setCount] = useState<number>(0)
return (
<>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</>
)
}

Sample Output :

  • Initially shows:
    Count: 0

  • After clicking button 3 times:
    Count: 3

Dynamic Layouts (App Router)


Used to define custom layout structures for specific route segments . This allows you to apply different headers, sidebars, or page structures depending on the route.

Folder Structure Example:

app/
├── dashboard/
│ ├── layout.tsx ← Layout specific to /dashboard/*
│ └── page.tsx ← Main dashboard page
|
└── layout.tsx ← Root layout (wraps everything)
  • The root layout.tsx is the top-level layout that defines the overall structure of your app.

  • The dashboard/layout.tsx wraps all routes under /dashboard — for example: /dashboard, /dashboard/settings etc.

Common Use Case: For example, to create a layout for the /blog route, add a new layout file inside the blog folder.

RootLayout

app/layout.tsx
import React from 'react'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
<header>Global Header</header>
<main>{children}</main>
<footer>© 2025 All Rights Reserved</footer>
</body>
</html>
)
}

BlogLayout

app/blog/layout.tsx
import React from 'react'
export default function BlogLayout({ children }: { children: React.ReactNode }) {
return (
<div>
<header>Blog Header</header>
<main>{children}</main>
</div>
)
}

When a user visits /blog, the RootLayout renders first, and inside its <main>, the BlogLayout renders its own structure with the corresponding page content.