Next.js is a powerful React framework that enhances the developer experience by offering features like file-based routing, server-side rendering, and API routes out of the box. In this post, we’ll cover the core concepts of Next.js to help you build scalable and efficient web applications.
Pages and Routing
Next.js simplifies routing with its file-based system. Each file in the pages/
directory automatically becomes a route.
File-based Routing
Example:
/pages
index.js → "/"
about.js → "/about"
// pages/index.js
export default function Home() {
return <h1>Welcome to Next.js!</h1>;
}
Dynamic Routes
Dynamic routes are created using square brackets.
Example:
/pages/product/[id].js
import { useRouter } from 'next/router';
export default function Product() {
const { query } = useRouter();
return <h1>Product ID: {query.id}</h1>;
}
Catch-All Routes
Capture multiple segments with [...param]
.
Example:
/pages/blog/[...slug].js
Rendering Methods
Next.js supports multiple rendering strategies:
App Router and Page Router
The App Router simplifies modern rendering, while the Page Router is the legacy system. Both coexist but prefer the App Router for new projects.
Server-Side Rendering (SSR)
Fetch data on the server at request time.
export async function getServerSideProps() {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
return { props: { data } };
}
export default function Page({ data }) {
return <pre>{JSON.stringify(data, null, 2)}</pre>;
}
Client-Side Rendering (CSR)
Use useEffect
to fetch data on the client.
import { useState, useEffect } from 'react';
export default function Page() {
const [data, setData] = useState(null);
useEffect(() => {
fetch('/api/data')
.then((res) => res.json())
.then(setData);
}, []);
return <pre>{JSON.stringify(data, null, 2)}</pre>;
}
API Routes
Next.js allows you to create backend endpoints in the pages/api
directory.
Creating Endpoints
Example:
// pages/api/hello.js
export default function handler(req, res) {
res.status(200).json({ message: 'Hello, World!' });
}
Handling Requests
Use req
and res
objects to handle different HTTP methods.
Example:
// pages/api/user.js
export default function handler(req, res) {
if (req.method === 'POST') {
res.status(201).json({ message: 'User created' });
} else {
res.status(405).json({ error: 'Method not allowed' });
}
}
Assets, Metadata, and Styles
Images and Assets
Optimize images with the next/image
component.
Example:
import Image from 'next/image';
export default function Home() {
return <Image src="/logo.png" alt="Logo" width={200} height={200} />;
}
Metadata with next/head
Add SEO-friendly metadata.
Example:
import Head from 'next/head';
export default function Home() {
return (
<>
<Head>
<title>My Next.js App</title>
<meta name="description" content="A great app built with Next.js" />
</Head>
<h1>Welcome!</h1>
</>
);
}
Styles
Next.js supports global styles and CSS modules.
Global Styles: Add styles in styles/globals.css
and import in _app.js
.
// pages/_app.js
import '../styles/globals.css';
export default function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />;
}
CSS Modules: Scoped styles for specific components.
// components/Button.module.css
.button {
background-color: blue;
color: white;
}
// components/Button.js
import styles from './Button.module.css';
export default function Button() {
return <button className={styles.button}>Click Me</button>;
}
Performance Optimizations
Lazy Loading
Optimize performance by lazy-loading components or images.
Example:
import dynamic from 'next/dynamic';
const DynamicComponent = dynamic(() => import('../components/HeavyComponent'));
export default function Home() {
return <DynamicComponent />;
}
Optimizing Images and Scripts
The next/image
component automatically optimizes images for size and format. Use next/script
to load third-party scripts efficiently.
Conclusion
Next.js bridges the gap between frontend and backend, offering a robust framework for building modern web applications. From routing and rendering to API endpoints and performance optimizations, mastering Next.js unlocks endless possibilities for developers.
Stay tuned for the next post in the Frontend Unlocked series, where we’ll explore advanced Next.js techniques and best practices!