Khi bước chân vào thế giới Next.js, hai khái niệm đầu tiên bạn cần nắm vững chính là Cấu trúc thư mục và Cơ chế Routing. Chúng không chỉ là những tệp tin và thư mục vô tri, mà là bộ xương sống, là bản đồ định hình nên toàn bộ ứng dụng của bạn. Hiểu rõ chúng cũng giống như một kiến trúc sư hiểu rõ bản thiết kế của tòa nhà trước khi đặt viên gạch đầu tiên.
Bài viết này sẽ giúp bạn làm chủ hai khái niệm cốt lõi này, từ cách tiếp cận truyền thống với Pages Router
đến cuộc cách mạng hiện đại mang tên App Router
.
Tại sao cấu trúc thư mục lại quan trọng đến vậy? 🏗️
Trong Next.js, cấu trúc thư mục không đơn thuần là nơi bạn "vứt" code vào. Nó tuân theo triết lý "Convention over Configuration" (Ưu tiên quy ước hơn cấu hình). Điều này có nghĩa là:
- Tên file và thư mục có ý nghĩa: Cách bạn đặt tên và sắp xếp file sẽ tự động tạo ra các đường dẫn (routes) cho trang web.
- Dự đoán được: Bất kỳ ai quen thuộc với Next.js đều có thể nhanh chóng hiểu được luồng hoạt động của ứng dụng chỉ bằng cách nhìn vào cấu trúc thư mục.
- Tích hợp sẵn các tính năng: Các file với tên đặc biệt (như
layout.tsx
,page.tsx
,loading.tsx
) sẽ được Next.js tự động nhận diện và trao cho những "siêu năng lực" riêng.
Hãy coi cấu trúc thư mục là bản giao kèo giữa bạn và Next.js. Bạn tuân thủ quy ước, và Next.js sẽ lo phần còn lại một cách kỳ diệu.
Cuộc cách mạng Routing: App Router vs. Pages Router 🗺️
Next.js đã trải qua một bước tiến hóa lớn với sự ra đời của App Router (trong thư mục app
) để thay thế cho Pages Router (trong thư mục pages
) truyền thống. Các dự án mới nên bắt đầu với App Router
, nhưng việc hiểu cả hai là rất quan trọng để có thể làm việc trên các dự án cũ hơn.
1. App Router (Cách tiếp cận hiện đại - Khuyến nghị)
Đây là tương lai của Next.js, được giới thiệu từ phiên bản 13 và trở thành mặc định. Nó mạnh mẽ hơn, linh hoạt hơn và được xây dựng dựa trên React Server Components.
File và Thư mục đặc biệt trong app
Thư mục app
là trung tâm của mọi thứ. Mỗi thư mục con bên trong app
sẽ tương ứng với một phân đoạn trên URL.
app/layout.tsx
: File BẮT BUỘC. Đây là "bộ khung" chung cho toàn bộ ứng dụng của bạn. Nó chứa các thẻ<html>
và<body>
, là nơi tuyệt vời để đặt header, footer, sidebar và các provider (như Redux, Context API). Mọi trang khác sẽ được "lồng" vào bên trong layout này.app/page.tsx
: Đây là trang chủ (homepage) của bạn, tương ứng với URL/
.app/dashboard/page.tsx
: Cấu trúc này sẽ tự động tạo ra một trang tại URL/dashboard
.app/blog/[slug]/page.tsx
: Đây là một Dynamic Route (Route động).[slug]
là một tham số động, có thể là bất cứ chuỗi nào. Ví dụ:/blog/bai-viet-1
,/blog/hoc-nextjs-co-ban
. Bạn sẽ lấy giá trịslug
để truy vấn dữ liệu tương ứng.
Các "siêu năng lực" của App Router
Bên cạnh page.tsx
, bạn có thể tạo thêm các file đặc biệt trong cùng một thư mục để tự động xử lý các trạng thái giao diện khác nhau:
loading.tsx
: Hiển thị một giao diện loading (ví dụ: spinner) trong khi dữ liệu củapage.tsx
đang được tải. Next.js sẽ tự động hiển thị file này và thay thế bằngpage.tsx
khi tải xong.error.tsx
: Một "lưới an toàn". Nếu có lỗi xảy ra trong quá trình render trang, nội dung của file này sẽ được hiển thị thay vì làm sập toàn bộ ứng dụng.not-found.tsx
: Tự động hiển thị khi người dùng truy cập một URL không tồn tại trong phân đoạn đó.template.tsx
: Tương tự nhưlayout.tsx
nhưng không duy trì state khi chuyển trang. Hữu ích cho các hiệu ứng animation khi vào/ra trang.
Ví dụ cấu trúc App Router hoàn chỉnh:
/app
├── layout.tsx # Layout gốc cho toàn bộ ứng dụng
├── page.tsx # Trang chủ (/)
│
├── /blog
│ ├── page.tsx # Trang danh sách blog (/blog)
│ ├── /[slug]
│ │ ├── page.tsx # Trang chi tiết bài viết (/blog/...)
│ │ ├── loading.tsx # Giao diện tải cho trang chi tiết
│
├── /dashboard
│ ├── layout.tsx # Layout riêng cho khu vực dashboard
│ ├── page.tsx # Trang chính của dashboard (/dashboard)
│ ├── /settings
│ │ ├── page.tsx # Trang cài đặt (/dashboard/settings)
2. Pages Router (Cách tiếp cận truyền thống)
Nếu bạn làm việc với một dự án Next.js cũ hơn, bạn sẽ thấy thư mục pages
. Cơ chế hoạt động của nó đơn giản hơn nhưng cũng kém linh hoạt hơn.
File và Thư mục đặc biệt trong pages
pages/index.tsx
: Trang chủ của bạn (/
).pages/about.tsx
: Tự động tạo trang tại/about
.pages/posts/[id].tsx
: Một route động. Ví dụ:/posts/123
.pages/_app.tsx
: File này bao bọc tất cả các trang khác. Đây là nơi để thêm layout chung, global CSS, và state. Tương đương vớiapp/layout.tsx
.pages/_document.tsx
: Tùy chỉnh cấu trúc HTML gốc (<html>
,<head>
,<body>
). File này ít khi cần chỉnh sửa.pages/api/
...: Bất kỳ file nào trong thư mụcpages/api
sẽ trở thành một API endpoint, không phải là một trang giao diện. Ví dụ:pages/api/user.ts
sẽ tạo ra endpoint/api/user
. Đây là một tính năng cực kỳ mạnh mẽ để xây dựng backend ngay trong Next.js.
Routing trong thực tế: Các mẫu hình cơ bản 💡
Dù bạn dùng App Router hay Pages Router, các khái niệm routing cốt lõi vẫn tương tự.
Routing tĩnh (Static Routing)
Đây là dạng cơ bản nhất. Một file tương ứng với một URL cố định.
app/contact/page.tsx
→/contact
pages/pricing.tsx
→/pricing
Routing động (Dynamic Routing)
Khi bạn cần tạo ra các trang từ dữ liệu, ví dụ như trang chi tiết sản phẩm hoặc bài viết blog.
- App Router:
app/products/[productId]/page.tsx
- Pages Router:
pages/products/[productId].tsx
Cả hai đều sẽ khớp với các URL như /products/1
, /products/abc
, v.v. Bạn có thể truy cập vào productId
từ params trong component của mình.
Routing lồng nhau (Nested Routing)
Tạo các thư mục con để có các URL lồng nhau.
app/dashboard/analytics/page.tsx
→/dashboard/analytics
pages/dashboard/analytics.tsx
→/dashboard/analytics
Điều hướng giữa các trang
Để di chuyển giữa các trang, bạn không dùng thẻ <a>
thông thường vì nó sẽ tải lại toàn bộ trang. Thay vào đó, hãy dùng component <Link>
của Next.js để có trải nghiệm chuyển trang siêu mượt mà (Client-Side Navigation).
import Link from 'next/link'
function Navbar() {
return (
<nav>
<Link href="/">Trang Chủ</Link>
<Link href="/about">Giới Thiệu</Link>
<Link href="/blog/my-first-post">Bài Viết Đầu Tiên</Link>
</nav>
)
}
Thư mục quan trọng khác 📂
Ngoài app
và pages
, một dự án Next.js điển hình còn có:
/public
: Chứa các tài nguyên tĩnh như hình ảnh, fonts,favicon.ico
. Bất kỳ thứ gì trong này đều có thể được truy cập trực tiếp từ URL gốc. Ví dụ:public/logo.png
sẽ có thể được truy cập tạiyourdomain.com/logo.png
./src
: Một thư mục tùy chọn. Nhiều người thích đặtapp
(hoặcpages
) và các thư mục code khác (như/components
,/lib
,/hooks
) vào trong/src
để dự án gọn gàng hơn./components
: Nơi chứa các component React tái sử dụng của bạn (nút bấm, card, form, v.v.)./lib
hoặc/utils
: Chứa các hàm tiện ích, logic nghiệp vụ có thể tái sử dụng trên toàn bộ ứng dụng.
Kết luận: Cần nắm vững Cấu trúc thư mục và Routing
Nắm vững Cấu trúc thư mục và Routing trong Next.js không chỉ giúp bạn viết code hiệu quả hơn mà còn mở ra cánh cửa để tận dụng toàn bộ sức mạnh của framework này. Hãy bắt đầu với App Router
cho các dự án mới, hiểu rõ các file đặc biệt như layout
, page
, loading
, và sử dụng <Link>
để tạo ra trải nghiệm người dùng liền mạch.
Khi cấu trúc dự án của bạn rõ ràng và logic, việc phát triển, bảo trì và mở rộng ứng dụng trong tương lai sẽ trở nên dễ dàng hơn rất nhiều. Chúc bạn thành công trên hành trình chinh phục Next.js!