Bài 28.2: Pages và routing trong Next.js

Bài 28.2: Pages và routing trong Next.js
Chào mừng các bạn trở lại với chuỗi bài viết về Lập trình Web Front-end! Hôm nay, chúng ta sẽ đi sâu vào một trong những tính năng cốt lõi và mạnh mẽ nhất của Next.js: cách nó quản lý các "Pages" (trang) và thiết lập hệ thống "Routing" (định tuyến) linh hoạt, hiệu quả.
Nếu bạn đã từng làm việc với các ứng dụng React truyền thống (kiểu SPA với Create React App), bạn có thể đã quen thuộc với việc cài đặt và cấu hình các thư viện routing như react-router-dom
. Next.js mang đến một cách tiếp cận hoàn toàn khác, đơn giản hơn nhiều nhưng cực kỳ mạnh mẽ: file-system routing.
Pages: Nền tảng của ứng dụng Next.js
Trong Next.js, một Page đơn giản là một React Component được export mặc định (default export) từ một file nằm trong thư mục đặc biệt. Thư mục này, kể từ Next.js 13 trở đi, được khuyến khích là thư mục app
.
Mỗi file trong thư mục app
(hoặc các thư mục con của nó) có tên là page.tsx
(hoặc .jsx
, .js
) sẽ tự động trở thành một trang trong ứng dụng của bạn.
Ví dụ đơn giản nhất: Trang chủ. Để tạo trang chủ (route
/
), bạn chỉ cần tạo một file tạiapp/page.tsx
.// app/page.tsx import React from 'react'; export default function HomePage() { return ( <div> <h1>Chào mừng đến với Trang Chủ!</h1> <p>Đây là nội dung của trang chủ.</p> </div> ); }
Giải thích: File
app/page.tsx
được đặt tại thư mục gốc củaapp
. Theo quy ước của Next.js, filepage.tsx
ở cấp cao nhất này sẽ tương ứng với URL gốc/
của trang web.
Routing: Sức mạnh từ cấu trúc file
Điểm thú vị và khác biệt của Next.js chính là cách nó xử lý routing. Thay vì cấu hình tuyến đường trong một file tập trung, Next.js sử dụng cấu trúc thư mục và tên file bên trong thư mục app
để định nghĩa các tuyến đường URL.
Ví dụ về Static Routing: Nếu bạn muốn tạo một trang "Giới thiệu" với URL
/about
, bạn chỉ cần tạo một thư mục conabout
bên trongapp
và đặt filepage.tsx
vào đó.// app/about/page.tsx import React from 'react'; export default function AboutPage() { return ( <div> <h1>Giới thiệu về chúng tôi</h1> <p>Đây là trang giới thiệu.</p> </div> ); }
Giải thích: Cấu trúc thư mục
app/about/
tương ứng với URL/about
. Filepage.tsx
bên trong thư mục đó là component sẽ được render khi người dùng truy cập/about
. Thật đơn giản phải không nào?Bạn có thể tạo các cấp độ lồng nhau tương tự:
app/products/page.tsx
->/products
app/dashboard/settings/page.tsx
->/dashboard/settings
Cấu trúc file trực quan hóa cấu trúc URL, giúp bạn dễ dàng tổ chức dự án và hiểu được các tuyến đường mà không cần nhìn vào file cấu hình routing riêng biệt.
Điều hướng giữa các Pages với <Link>
Trong các ứng dụng React truyền thống, bạn thường dùng thẻ <a>
để tạo liên kết. Tuy nhiên, thẻ <a>
thông thường sẽ gây ra tải lại toàn bộ trang (full page reload) khi chuyển hướng, làm mất đi trải nghiệm mượt mà của ứng dụng một trang (SPA).
Next.js cung cấp component <Link>
từ thư viện next/link
để xử lý việc này một cách thông minh. <Link>
cho phép chuyển hướng giữa các trang trong ứng dụng của bạn mà không cần tải lại toàn bộ trang, mang lại trải nghiệm người dùng nhanh chóng và liền mạch giống như một SPA thực thụ.
Ví dụ sử dụng
<Link>
: Để thêm liên kết từ trang chủ đến trang giới thiệu, bạn chỉnh sửa fileapp/page.tsx
như sau:// app/page.tsx import React from 'react'; import Link from 'next/link'; // Import component Link export default function HomePage() { return ( <div> <h1>Chào mừng đến với Trang Chủ!</h1> <p>Đây là nội dung của trang chủ.</p> <nav> {/* Sử dụng component Link để điều hướng */} <Link href="/about"> Đi đến trang Giới thiệu </Link> {/* <a href="/about">Sẽ tải lại trang</a> */} </nav> </div> ); }
Giải thích:
- Chúng ta import
Link
từnext/link
. - Component
<Link>
nhận prophref
là đường dẫn nội bộ của trang muốn đến (giống nhưhref
của thẻ<a>
). - Nội dung bên trong
<Link>
(ở đây là<Link href="/about">Đi đến trang Giới thiệu</Link>
) sẽ là element mà người dùng tương tác (ví dụ: văn bản, button, hình ảnh). Component<Link>
sẽ render ra thẻ<a>
thực tế vớihref
tương ứng, nhưng sẽ xử lý việc click để thực hiện chuyển hướng client-side thay vì tải lại trang.
- Chúng ta import
Next.js cũng hỗ trợ prefetching (tải trước) nội dung của các trang được liên kết khi chúng xuất hiện trong viewport, giúp việc chuyển trang diễn ra gần như tức thời.
Dynamic Routes: Xử lý các URL thay đổi
Không phải lúc nào các URL cũng cố định. Ví dụ, bạn có thể cần hiển thị thông tin chi tiết của một bài viết dựa trên ID hoặc slug của nó (ví dụ: /posts/bai-viet-a
, /posts/bai-viet-b
). Đây là lúc Dynamic Routes phát huy tác dụng.
Trong Next.js, bạn tạo dynamic route bằng cách sử dụng dấu ngoặc vuông []
trong tên thư mục. Tên bên trong dấu ngoặc vuông (ví dụ: [slug]
) sẽ trở thành tên tham số mà bạn có thể truy cập trong component trang của mình.
Ví dụ về Dynamic Route: Để tạo trang hiển thị chi tiết bài viết theo slug (ví dụ:
/blog/ten-bai-viet
), bạn tạo cấu trúc thư mụcapp/blog/[slug]/page.tsx
.// app/blog/[slug]/page.tsx import React from 'react'; // Next.js sẽ tự động truyền params vào component page export default function BlogPostPage({ params }: { params: { slug: string } }) { const postSlug = params.slug; // Ở đây, bạn có thể fetch dữ liệu bài viết dựa trên postSlug // Ví dụ: const postData = await fetchPostBySlug(postSlug); return ( <div> <h1>Chi tiết bài viết</h1> <p>Slug của bài viết này là: *_{postSlug}_*</p> {/* Render nội dung bài viết dựa trên postData */} </div> ); } // (Tùy chọn) Hàm này giúp tạo các trang tĩnh cho các slug cụ thể // Rất hữu ích cho các bài viết không thay đổi thường xuyên export async function generateStaticParams() { // Giả sử bạn có danh sách các slugs bài viết từ API hoặc database const slugs = ['bai-viet-a', 'bai-viet-b', 'mot-bai-khac']; // Ví dụ return slugs.map((slug) => ({ slug: slug, })); }
Giải thích:
- Thư mục
[slug]
bên trongapp/blog/
cho Next.js biết rằng bất kỳ URL nào khớp với pattern/blog/*
(ngoại trừ các route cố định khác trong/blog
) sẽ được xử lý bởi componentpage.tsx
này. - Tên bên trong dấu ngoặc vuông (
slug
) trở thành một key trong objectparams
được truyền vào component page. Bạn có thể truy cập giá trị thực tế từ URL thông quaparams.slug
. - Hàm
generateStaticParams
(chỉ có trong App Router) là một tính năng mạnh mẽ. Nó cho phép bạn định nghĩa trước các giá trịparams
(ở đây là cácslug
) mà Next.js sẽ sử dụng để pre-render (tạo tĩnh) các trang động này tại thời điểm build. Điều này giúp cải thiện hiệu suất và SEO đáng kể cho các trang có nội dung tĩnh hoặc ít thay đổi.
- Thư mục
Bạn có thể có nhiều dynamic segments trong một route (ví dụ: app/shop/[category]/[productId]/page.tsx
sẽ khớp với /shop/electronics/laptop-123
).
Tóm lại
Hệ thống Pages và Routing dựa trên cấu trúc file của Next.js là một cách tiếp cận độc đáo và hiệu quả để xây dựng các ứng dụng web hiện đại.
- Mỗi file
page.tsx
(hoặc.jsx
,.js
) trong thư mụcapp
(hoặc thư mục con) đại diện cho một trang tại một URL cụ thể. - Cấu trúc thư mục trong
app
trực tiếp ánh xạ tới cấu trúc URL. - Sử dụng component
<Link>
từnext/link
để điều hướng giữa các trang một cách mượt mà và hiệu quả (client-side navigation). - Dynamic Routes sử dụng cú pháp
[]
trong tên thư mục để xử lý các URL có chứa các tham số thay đổi (ví dụ:/blog/[slug]
).
Nắm vững khái niệm Pages và Routing là chìa khóa để xây dựng các ứng dụng Next.js có tổ chức, dễ bảo trì và đạt hiệu suất cao nhờ vào khả năng rendering mạnh mẽ của Next.js. Hãy thử nghiệm tạo các trang và liên kết khác nhau trong dự án Next.js của bạn để làm quen với cách hoạt động này nhé!
Comments