React & Next.js Topic
Next.js Introduction
What is Next.js?
Next.js is a React framework that provides a complete solution for production-grade React applications. While React is a library for building user interfaces, Next.js is a framework that builds upon React to provide additional features like routing, API routes, performance optimizations, and more - all configured and optimized out of the box.
Key Differentiators
| React Alone | Next.js |
|---|---|
| Library for UI components | Full framework for web applications |
| Client-side rendering by default | Multiple rendering methods |
| Manual routing setup | File-based routing |
| Separate API setup needed | Built-in API routes |
| Manual optimization | Automatic optimizations |
Core Next.js Concepts
1. File-Based Routing
Next.js uses the file system as the router. Every file in the pages (or app in App Router) directory becomes a route.
jsx
// pages/index.js → /
function HomePage() {
return <h1>Home Page</h1>;
}
export default HomePage;
// pages/about.js → /about
function AboutPage() {
return <h1>About Us</h1>;
}
export default AboutPage;
// pages/blog/[slug].js → /blog/hello-world, /blog/nextjs-guide
function BlogPost() {
const router = useRouter();
const { slug } = router.query;
return <h1>Blog Post: {slug}</h1>;
}
export default BlogPost;
2. Rendering Methods
Next.js provides multiple rendering strategies for different use cases:
Server-Side Rendering (SSR)
jsx
// pages/posts.js
function Posts({ posts }) {
return (
<div>
<h1>Posts</h1>
{posts.map(post => (
<div key={post.id}>{post.title}</div>
))}
</div>
);
}
// This runs on the server on each request
export async function getServerSideProps() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
return {
props: { posts } // will be passed to the page component
};
}
export default Posts;
Static Site Generation (SSG)
jsx
// pages/products.js
function Products({ products }) {
return (
<div>
<h1>Products</h1>
{products.map(product => (
<div key={product.id}>{product.name}</div>
))}
</div>
);
}
// This runs at build time
export async function getStaticProps() {
const res = await fetch('https://api.example.com/products');
const products = await res.json();
return {
props: { products },
revalidate: 60 // Regenerate page every 60 seconds (ISR)
};
}
export default Products;
Incremental Static Regeneration (ISR)
jsx
// pages/blog/[id].js
function BlogPost({ post }) {
return (
<article>
<h1>{post.title}</h1>
<p>{post.content}</p>
</article>
);
}
export async function getStaticPaths() {
// Pre-render these paths at build time
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
const paths = posts.map(post => ({
params: { id: post.id.toString() }
}));
return {
paths,
fallback: 'blocking' // Generate new pages on demand
};
}
export async function getStaticProps({ params }) {
const res = await fetch(`https://api.example.com/posts/${params.id}`);
const post = await res.json();
return {
props: { post },
revalidate: 3600 // Regenerate every hour
};
}
export default BlogPost;
Client-Side Rendering (CSR)
jsx
// pages/dashboard.js
import { useState, useEffect } from 'react';
function Dashboard() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('/api/user-data')
.then(res => res.json())
.then(data => {
setData(data);
setLoading(false);
});
}, []);
if (loading) return <div>Loading...</div>;
return (
<div>
<h1>Dashboard</h1>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}
export default Dashboard;
3. API Routes
Next.js allows you to build your API alongside your frontend.
jsx
// pages/api/users.js
export default function handler(req, res) {
const { method } = req;
switch (method) {
case 'GET':
// Get users from database
res.status(200).json([{ id: 1, name: 'John' }]);
break;
case 'POST':
// Create new user
const { name } = req.body;
res.status(201).json({ id: 2, name });
break;
default:
res.setHeader('Allow', ['GET', 'POST']);
res.status(405).end(`Method ${method} Not Allowed`);
}
}
// pages/api/users/[id].js
export default function handler(req, res) {
const { query: { id }, method } = req;
switch (method) {
case 'GET':
// Get user by ID
res.status(200).json({ id: parseInt(id), name: 'John' });
break;
case 'PUT':
// Update user
res.status(200).json({ id: parseInt(id), name: 'Updated Name' });
break;
case 'DELETE':
// Delete user
res.status(204).end();
break;
default:
res.setHeader('Allow', ['GET', 'PUT', 'DELETE']);
res.status(405).end(`Method ${method} Not Allowed`);
}
}
Next.js App Router (Version 13+)
The newer App Router uses a different structure with React Server Components.
App Router Structure
text
app/
├── layout.js # Root layout
├── page.js # Home page (/)
├── loading.js # Loading UI
├── globals.css # Global styles
├── dashboard/
│ ├── layout.js # Dashboard layout
│ ├── page.js # /dashboard
│ └── settings/
│ └── page.js # /dashboard/settings
└── api/
└── users/
└── route.js # API endpoint
Server Components by Default
jsx
// app/page.js - Server Component by default
async function HomePage() {
// This runs on the server
const data = await fetch('https://api.example.com/data', {
cache: 'force-cache' // SSG
// cache: 'no-store' // SSR
}).then(res => res.json());
return (
<main>
<h1>Home Page</h1>
<div>{data.message}</div>
<ClientComponent />
</main>
);
}
// This is a Client Component
'use client';
function ClientComponent() {
const [state, setState] = useState('');
return (
<div>
<input
value={state}
onChange={(e) => setState(e.target.value)}
/>
</div>
);
}
export default HomePage;
Layouts
jsx
// app/layout.js - Root layout
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<header>
<nav>Navigation</nav>
</header>
<main>{children}</main>
<footer>Footer</footer>
</body>
</html>
);
}
// app/dashboard/layout.js - Nested layout
export default function DashboardLayout({ children }) {
return (
<div className="dashboard-layout">
<aside>Dashboard Sidebar</aside>
<section>{children}</section>
</div>
);
}
Key Features
1. Image Optimization
jsx
import Image from 'next/image';
function MyComponent() {
return (
<div>
<Image
src="/profile.jpg"
alt="Profile picture"
width={500}
height={300}
priority // Load above the fold images first
placeholder="blur" // Add blur placeholder
blurDataURL="data:image/jpeg;base64,..."
/>
</div>
);
}
2. Font Optimization
jsx
// app/layout.js
import { Inter } from 'next/font/google';
const inter = Inter({ subsets: ['latin'] });
export default function RootLayout({ children }) {
return (
<html lang="en" className={inter.className}>
<body>{children}</body>
</html>
);
}
3. Script Optimization
jsx
import Script from 'next/script';
function MyComponent() {
return (
<>
<Script
src="https://analytics.example.com/script.js"
strategy="afterInteractive" // Load after page becomes interactive
onLoad={() => {
// Initialize analytics
}}
/>
</>
);
}
4. Metadata API
jsx
// app/page.js
export const metadata = {
title: 'Home Page',
description: 'Welcome to our website',
openGraph: {
title: 'Home Page',
description: 'Welcome to our website',
images: ['/og-image.jpg'],
},
};
// Or dynamically
export async function generateMetadata({ params }) {
const product = await fetchProduct(params.id);
return {
title: product.title,
description: product.description,
};
}
Getting Started
Installation
bash
# Create new Next.js app npx create-next-app@latest my-app cd my-app # Start development server npm run dev # Build for production npm run build # Start production server npm start
Project Structure
text
my-app/ ├── app/ # App Router (v13+) │ ├── layout.js │ ├── page.js │ └── globals.css ├── pages/ # Pages Router (legacy) │ ├── api/ │ ├── _app.js │ └── index.js ├── public/ # Static assets ├── components/ # Reusable components ├── lib/ # Utilities ├── styles/ # CSS modules └── next.config.js # Next.js configuration
When to Use Next.js
Choose Next.js when you need:
✅ SEO optimization - Server-side rendering helps search engines
✅ Performance - Automatic code splitting, image optimization
✅ Full-stack capabilities - API routes + frontend in one project
✅ Production-ready features - Built-in optimizations and best practices
✅ Fast development - Zero-config setup with sensible defaults
✅ Scalability - Handles large applications efficiently
Comments (0)
No comments yet. Be the first to comment!