avatar
Siz Long

My name is Siz. I am a computer science graduate student specializing in backend development with Golang and Python, seeking opportunities in innovative tech projects. My personal website is me.longsizhuo.com .Connect with me on LinkedIn: https://www.linkedin.com/in/longsizhuo/.

  • Resume
  • Archives
  • Categories
  • Photos
  • Music



{{ date }}

{{ time }}

avatar
Siz Long

My name is Siz. I am a computer science graduate student specializing in backend development with Golang and Python, seeking opportunities in innovative tech projects. My personal website is me.longsizhuo.com .Connect with me on LinkedIn: https://www.linkedin.com/in/longsizhuo/.

  • 主页
  • Resume
  • Archives
  • Categories
  • Photos
  • Music

Next.js Fundamentals

  2023-06-11        
字数统计: 2.8k字   |   阅读时长: 17min

Next.js Fundamentals

Next.js is a React framework that enables server-side rendering, static site generation, and other advanced features with minimal configuration.

Introduction to Next.js

Next.js was created by Vercel and provides:

  • Server-side rendering (SSR): Renders pages on the server for better SEO and initial load performance
  • Static site generation (SSG): Pre-renders pages at build time for optimal performance
  • Automatic code splitting: Only loads JavaScript needed for each page
  • Built-in CSS/Sass support: Import CSS/Sass files directly in components
  • API routes: Create API endpoints as Node.js serverless functions
  • Developer experience: Hot reloading, error reporting, and more

Setting Up a Next.js Project

Creating a New Project

1
2
3
npx create-next-app my-nextjs-app
cd my-nextjs-app
npm run dev

Project Structure

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
my-nextjs-app/
├── .next/ # Build output directory
├── node_modules/ # Dependencies
├── pages/ # Application pages and API routes
│ ├── api/ # API routes
│ ├── _app.js # Custom App component
│ ├── _document.js # Custom Document component
│ └── index.js # Home page
├── public/ # Static assets
├── styles/ # CSS/Sass files
├── components/ # React components
├── .gitignore # Git ignore file
├── next.config.js # Next.js configuration
├── package.json # Project dependencies and scripts
└── README.md # Project documentation

Pages and Routing

Next.js has a file-system based router built on the concept of pages:

Basic Pages

1
2
3
4
5
6
7
8
9
// pages/index.js - Route: /
export default function Home() {
return <h1>Home Page</h1>;
}

// pages/about.js - Route: /about
export default function About() {
return <h1>About Page</h1>;
}

Dynamic Routes

1
2
3
4
5
6
7
8
9
// pages/posts/[id].js - Route: /posts/:id
import { useRouter } from 'next/router';

export default function Post() {
const router = useRouter();
const { id } = router.query;

return <h1>Post: {id}</h1>;
}

Nested Dynamic Routes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// pages/[category]/[product].js - Route: /:category/:product
import { useRouter } from 'next/router';

export default function Product() {
const router = useRouter();
const { category, product } = router.query;

return (
<div>
<h1>Category: {category}</h1>
<h2>Product: {product}</h2>
</div>
);
}

Catch-All Routes

1
2
3
4
5
6
7
8
9
10
// pages/blog/[...slug].js - Routes: /blog/2020/01/01, /blog/category/post
import { useRouter } from 'next/router';

export default function BlogPost() {
const router = useRouter();
const { slug } = router.query;
// slug will be an array like ['2020', '01', '01'] or ['category', 'post']

return <h1>Blog Post: {slug?.join('/')}</h1>;
}

Navigation

Link Component

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import Link from 'next/link';

export default function Navigation() {
return (
<nav>
<Link href="/">Home</Link>
<Link href="/about">About</Link>
<Link href="/blog/hello-world">Blog Post</Link>

{/* With dynamic route */}
<Link href={`/posts/${postId}`}>Post</Link>

{/* With object syntax for complex paths */}
<Link href={{
pathname: '/posts/[id]',
query: { id: postId },
}}>
Post
</Link>
</nav>
);
}

Programmatic Navigation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { useRouter } from 'next/router';

export default function LoginButton() {
const router = useRouter();

function handleLogin() {
// Authenticate user
router.push('/dashboard');

// Or with dynamic route
router.push(`/profile/${userId}`);

// Or with URL object
router.push({
pathname: '/posts/[id]',
query: { id: postId },
});
}

return <button onClick={handleLogin}>Log in</button>;
}

Data Fetching

Next.js has built-in data fetching methods for different use cases:

getStaticProps (Static Site Generation)

Use for data available at build time:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// pages/posts.js
export default function Posts({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}

// This runs at build time in production
export async function getStaticProps() {
const res = await fetch('https://jsonplaceholder.typicode.com/posts');
const posts = await res.json();

return {
props: {
posts,
},
// Revalidate every 10 seconds (incremental static regeneration)
revalidate: 10,
};
}

getStaticPaths (Dynamic Routes with SSG)

Use with dynamic routes and getStaticProps:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// pages/posts/[id].js
export default function Post({ post }) {
return (
<div>
<h1>{post.title}</h1>
<p>{post.body}</p>
</div>
);
}

// Generate the paths at build time
export async function getStaticPaths() {
const res = await fetch('https://jsonplaceholder.typicode.com/posts');
const posts = await res.json();

// Get the paths we want to pre-render
const paths = posts.slice(0, 10).map((post) => ({
params: { id: post.id.toString() },
}));

return {
paths,
// fallback: false means other routes 404
// fallback: true generates pages on demand
// fallback: 'blocking' is similar but waits for generation
fallback: 'blocking',
};
}

// Fetch data for each page
export async function getStaticProps({ params }) {
const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${params.id}`);
const post = await res.json();

// If no post is found, return 404
if (!post.id) {
return {
notFound: true,
};
}

return {
props: {
post,
},
revalidate: 60, // Regenerate after 60 seconds
};
}

getServerSideProps (Server-Side Rendering)

Use for data that must be fetched at request time:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// pages/profile.js
export default function Profile({ user }) {
return (
<div>
<h1>{user.name}</h1>
<p>Email: {user.email}</p>
</div>
);
}

// This runs on every request
export async function getServerSideProps(context) {
// context contains request parameters, headers, cookies
const { req, res, params, query } = context;

// Example: cookie-based authentication
const cookies = req.headers.cookie;

// Fetch data from an API
const response = await fetch('https://api.example.com/user', {
headers: {
cookie: cookies
}
});

const user = await response.json();

// Redirect if not authenticated
if (!user) {
return {
redirect: {
destination: '/login',
permanent: false,
},
};
}

return {
props: {
user,
},
};
}

Client-Side Data Fetching

For data that doesn’t need SEO or can be loaded after the page loads:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { useState, useEffect } from 'react';

export default function Dashboard() {
const [data, setData] = useState(null);
const [isLoading, setIsLoading] = useState(true);

useEffect(() => {
async function fetchData() {
const response = await fetch('/api/dashboard-data');
const data = await response.json();
setData(data);
setIsLoading(false);
}

fetchData();
}, []);

if (isLoading) return <p>Loading...</p>;
if (!data) return <p>No data</p>;

return (
<div>
<h1>Dashboard</h1>
<p>Total users: {data.totalUsers}</p>
</div>
);
}

SWR for Data Fetching

Next.js recommends SWR for client-side data fetching:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import useSWR from 'swr';

// Reusable fetcher function
const fetcher = (url) => fetch(url).then((res) => res.json());

export default function Profile() {
const { data, error, isLoading } = useSWR('/api/user', fetcher);

if (error) return <div>Failed to load</div>;
if (isLoading) return <div>Loading...</div>;

return (
<div>
<h1>Hello {data.name}!</h1>
<p>Email: {data.email}</p>
</div>
);
}

API Routes

Next.js allows you to create API endpoints within your application:

1
2
3
4
// pages/api/hello.js
export default function handler(req, res) {
res.status(200).json({ message: 'Hello World!' });
}

Request Methods

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// pages/api/users.js
export default function handler(req, res) {
const { method } = req;

switch (method) {
case 'GET':
// Get data from your database
res.status(200).json({ users: ['John', 'Jane'] });
break;
case 'POST':
// Create data in your database
res.status(201).json({ message: 'User created' });
break;
default:
res.setHeader('Allow', ['GET', 'POST']);
res.status(405).end(`Method ${method} Not Allowed`);
}
}

Dynamic API Routes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// pages/api/users/[id].js
export default function handler(req, res) {
const { id } = req.query;
const { method } = req;

switch (method) {
case 'GET':
// Get user data from your database
res.status(200).json({ id, name: `User ${id}` });
break;
case 'PUT':
// Update user data in your database
res.status(200).json({ id, message: 'User updated' });
break;
case 'DELETE':
// Delete user data from your database
res.status(200).json({ id, message: 'User deleted' });
break;
default:
res.setHeader('Allow', ['GET', 'PUT', 'DELETE']);
res.status(405).end(`Method ${method} Not Allowed`);
}
}

Styling in Next.js

Next.js supports various styling options:

Global CSS

1
2
3
4
5
6
// pages/_app.js
import '../styles/globals.css';

export default function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />;
}

CSS Modules

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// styles/Home.module.css
.container {
min-height: 100vh;
padding: 0 0.5rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}

// pages/index.js
import styles from '../styles/Home.module.css';

export default function Home() {
return (
<div className={styles.container}>
<h1>Hello Next.js</h1>
</div>
);
}

Sass/SCSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Install Sass
// npm install sass

// styles/Home.module.scss
.container {
min-height: 100vh;

.title {
color: #0070f3;
text-decoration: none;

&:hover {
text-decoration: underline;
}
}
}

// pages/index.js
import styles from '../styles/Home.module.scss';

export default function Home() {
return (
<div className={styles.container}>
<h1 className={styles.title}>Hello Next.js</h1>
</div>
);
}

CSS-in-JS (Styled JSX)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
export default function Button() {
return (
<>
<button>Click me</button>
<style jsx>{`
button {
background: #0070f3;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background: #0051a2;
}
`}</style>
</>
);
}

Image Optimization

Next.js includes an Image component for automatic image optimization:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import Image from 'next/image';

export default function Avatar() {
return (
<div>
{/* Local images require width and height */}
<Image
src="/profile.jpg" // Route to the image file in public directory
alt="Profile"
width={500}
height={500}
priority // Load image immediately (LCP)
/>

{/* Remote images require width, height, or layout="fill" */}
<Image
src="https://example.com/profile.jpg"
alt="Profile"
width={500}
height={500}
loader={customLoader} // Optional custom loader
/>

{/* Fill container (parent must have position: relative) */}
<div style={{ position: 'relative', width: '100%', height: '300px' }}>
<Image
src="/banner.jpg"
alt="Banner"
fill
style={{ objectFit: 'cover' }}
/>
</div>
</div>
);
}

Head Management

Next.js has a built-in component for managing <head> elements:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import Head from 'next/head';

export default function Page() {
return (
<>
<Head>
<title>My Page Title</title>
<meta name="description" content="My page description" />
<meta property="og:title" content="My Page Title" />
<meta property="og:description" content="My page description" />
<meta property="og:image" content="https://example.com/og-image.jpg" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
<h1>Welcome to my page</h1>
</main>
</>
);
}

Custom Document and App

Custom Document

Customize the HTML document structure:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// pages/_document.js
import Document, { Html, Head, Main, NextScript } from 'next/document';

export default class MyDocument extends Document {
render() {
return (
<Html lang="en">
<Head>
<link
href="https://fonts.googleapis.com/css2?family=Inter&display=swap"
rel="stylesheet"
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}

Custom App

For persistent layouts, global state, or additional providers:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// pages/_app.js
import '../styles/globals.css';
import Layout from '../components/Layout';
import { ThemeProvider } from '../context/ThemeContext';

export default function MyApp({ Component, pageProps }) {
// Use the layout defined at the page level, if available
const getLayout = Component.getLayout || ((page) => <Layout>{page}</Layout>);

return (
<ThemeProvider>
{getLayout(<Component {...pageProps} />)}
</ThemeProvider>
);
}

// pages/index.js - Example of page-level layout
import AdminLayout from '../components/AdminLayout';

export default function Home() {
return <h1>Home Page</h1>;
}

// Define a custom layout for this page
Home.getLayout = function getLayout(page) {
return <AdminLayout>{page}</AdminLayout>;
};

Environment Variables

Next.js comes with built-in support for environment variables:

1
2
3
4
5
# .env.local (not committed to git)
DB_PASSWORD=supersecretpassword

# .env (committed to git)
NEXT_PUBLIC_API_URL=https://api.example.com
1
2
3
4
5
// Access in Node.js environment (SSR, API routes)
console.log(process.env.DB_PASSWORD);

// Access in browser (must be prefixed with NEXT_PUBLIC_)
console.log(process.env.NEXT_PUBLIC_API_URL);

Deployment

Static Export

For static sites that can be hosted anywhere:

1
2
3
4
5
6
7
# Configure in next.config.js
module.exports = {
output: 'export',
}

# Build and export
npm run build

Vercel (Recommended)

Deploy directly from Git:

1
2
3
4
5
# Install Vercel CLI
npm install -g vercel

# Deploy
vercel

Other Hosting Providers

For Node.js hosting:

1
2
3
4
5
# Build the application
npm run build

# Start the production server
npm start

Advanced Features

Middleware

Execute code before requests are completed:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
// Get a cookie
const theme = request.cookies.get('theme');

// Clone the request headers
const requestHeaders = new Headers(request.headers);

// Set a request header
requestHeaders.set('x-theme', theme?.value || 'light');

// You can also redirect
if (!request.cookies.get('authenticated') && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url));
}

// Continue the request with modified headers
return NextResponse.next({
request: {
headers: requestHeaders,
},
});
}

// Configure which paths should be matched
export const config = {
matcher: ['/dashboard/:path*', '/api/:path*'],
};

Internationalized Routing

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// next.config.js
module.exports = {
i18n: {
// Locales you want to support
locales: ['en', 'fr', 'es'],
// Default locale
defaultLocale: 'en',
// Domain-specific locales
domains: [
{
domain: 'example.com',
defaultLocale: 'en',
},
{
domain: 'example.fr',
defaultLocale: 'fr',
},
{
domain: 'example.es',
defaultLocale: 'es',
},
],
},
};

// Use in components
import { useRouter } from 'next/router';

export default function LocaleSwitcher() {
const router = useRouter();
const { locales, locale: activeLocale } = router;

const handleLocaleChange = (e) => {
const locale = e.target.value;
router.push(router.pathname, router.asPath, { locale });
};

return (
<select
onChange={handleLocaleChange}
defaultValue={activeLocale}
>
{locales.map((locale) => (
<option key={locale} value={locale}>
{locale}
</option>
))}
</select>
);
}

Best Practices

  1. Use Static Generation when possible for better performance
  2. Incremental Static Regeneration for dynamic content that changes infrequently
  3. Server-Side Rendering for pages that need request-time data
  4. Client-side fetching for private, user-specific data
  5. Optimize images with the Next.js Image component
  6. Code splitting happens automatically per page
  7. Pre-fetch links automatically with the Link component
  8. API Routes for backend functionality instead of external APIs
  9. Environment Variables for configuration
  10. TypeScript support for better developer experience

Learning Resources

  • Next.js Documentation
  • Next.js GitHub Repository
  • Next.js Learn Course
  • Vercel Tutorials
  • Next.js Discord Community
  • Next.js Weekly Newsletter
  • Mastering Next.js
  • Web Development
  • JavaScript
  • React
  • Frontend Framework
  • Next.js
  • SSR

扫一扫,分享到微信

微信分享二维码
Frontend Interview Preparation Guide
React Hooks
目录
  1. 1. Next.js Fundamentals
    1. 1.1. Introduction to Next.js
    2. 1.2. Setting Up a Next.js Project
      1. 1.2.1. Creating a New Project
      2. 1.2.2. Project Structure
    3. 1.3. Pages and Routing
      1. 1.3.1. Basic Pages
      2. 1.3.2. Dynamic Routes
      3. 1.3.3. Nested Dynamic Routes
      4. 1.3.4. Catch-All Routes
    4. 1.4. Navigation
      1. 1.4.1. Link Component
      2. 1.4.2. Programmatic Navigation
    5. 1.5. Data Fetching
      1. 1.5.1. getStaticProps (Static Site Generation)
      2. 1.5.2. getStaticPaths (Dynamic Routes with SSG)
      3. 1.5.3. getServerSideProps (Server-Side Rendering)
      4. 1.5.4. Client-Side Data Fetching
      5. 1.5.5. SWR for Data Fetching
    6. 1.6. API Routes
      1. 1.6.1. Request Methods
      2. 1.6.2. Dynamic API Routes
    7. 1.7. Styling in Next.js
      1. 1.7.1. Global CSS
      2. 1.7.2. CSS Modules
      3. 1.7.3. Sass/SCSS
      4. 1.7.4. CSS-in-JS (Styled JSX)
    8. 1.8. Image Optimization
    9. 1.9. Head Management
    10. 1.10. Custom Document and App
      1. 1.10.1. Custom Document
      2. 1.10.2. Custom App
    11. 1.11. Environment Variables
    12. 1.12. Deployment
      1. 1.12.1. Static Export
      2. 1.12.2. Vercel (Recommended)
      3. 1.12.3. Other Hosting Providers
    13. 1.13. Advanced Features
      1. 1.13.1. Middleware
      2. 1.13.2. Internationalized Routing
    14. 1.14. Best Practices
    15. 1.15. Learning Resources

150 篇 | 131.7k
次 | 人
这里自动载入天数这里自动载入时分秒
2022-2025 loong loong | 新南威尔士龙龙号