Menu

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!

LecturreAI Assistant

Hello! I'm LecturreAI

What would you like to learn today?