[React Basics] Dynamic Routes trong React: Bí quyết tạo nên ứng dụng linh hoạt

Nếu bạn đã từng xây dựng một ứng dụng React với nhiều trang, hẳn bạn đã quen thuộc với việc định tuyến. Bạn có một trang "Giới thiệu" tại /about, một trang "Liên hệ" tại /contact. Đây là những routes tĩnh (static routes) - đơn giản và dễ đoán.

Nhưng điều gì sẽ xảy ra khi bạn xây dựng một trang thương mại điện tử với hàng ngàn sản phẩm? Một blog với hàng trăm bài viết? Hay một mạng xã hội với hàng triệu hồ sơ người dùng? Chẳng lẽ chúng ta phải tạo ra hàng ngàn component Route khác nhau? 🤯

Dynamic Routes trong React: Bí quyết tạo nên ứng dụng linh hoạt

Câu trả lời chính là Dynamic Routes (routes động) - một khái niệm nền tảng, mạnh mẽ và là chìa khóa để xây dựng các ứng dụng React hiện đại, có khả năng mở rộng. Hãy cùng nhau khám phá "ma thuật" đằng sau nó nhé!

Dynamic Routes là gì? Một cách hiểu đơn giản 💡

Hãy tưởng tượng Dynamic Route như một tấm biển chỉ đường có chỗ trống. Thay vì chỉ dẫn đến một địa chỉ cố định duy nhất, nó chỉ dẫn đến một loại địa điểm, và bạn có thể điền vào phần còn trống để đến nơi cụ thể.

  • Route tĩnh: /about (Luôn luôn là trang Giới thiệu)
  • Route động: /products/:productId (Có thể là trang cho sản phẩm có ID là 1, 123, hay apple-iphone-15)

Cú pháp :productId chính là phần "động". Nó là một tham số (parameter) mà chúng ta có thể lấy và sử dụng bên trong component của mình. Thay vì tạo một route cho mỗi sản phẩm, chúng ta chỉ cần tạo một route duy nhất làm khuôn mẫu cho tất cả các trang chi tiết sản phẩm.

Tại sao không thể "sống" thiếu Dynamic Routes?

Sử dụng Dynamic Routes không chỉ là một lựa chọn, mà là một yêu cầu tất yếu để xây dựng ứng dụng phức tạp. Lợi ích nó mang lại là vô cùng to lớn:

  1. Khả năng mở rộng (Scalability): Đây là lợi ích lớn nhất. Bạn chỉ cần viết code cho một component mẫu (template), và nó có thể hiển thị dữ liệu cho vô số các mục khác nhau (sản phẩm, bài viết, người dùng,...). Ứng dụng của bạn có thể phát triển từ 10 sản phẩm lên 10,000 sản phẩm mà không cần thay đổi cấu trúc route.
  2. Tổ chức code sạch sẽ (Clean Code): Thay vì có một file routes.js dài hàng ngàn dòng hay một thư mục pages với hàng trăm file component, bạn chỉ cần một vài component mẫu được tổ chức gọn gàng.
  3. Trải nghiệm người dùng tốt hơn (Better UX): Dynamic Routes tạo ra các URL sạch sẽ, có ý nghĩa và dễ dàng chia sẻ (ví dụ: your-site.com/blog/cach-hoc-react-hieu-qua). Người dùng có thể đánh dấu trang (bookmark) và quay lại đúng nội dung họ đã xem.
  4. Thân thiện với SEO (SEO-Friendly): Các công cụ tìm kiếm như Google ưa thích các URL có cấu trúc rõ ràng và chứa từ khóa. Một URL như /products/samsung-galaxy-s25 tốt hơn nhiều so với /products?id=789.

"Thực chiến" với React Router DOM 🛠️

Thư viện phổ biến nhất để xử lý routing trong React là react-router-dom. Hãy xem cách chúng ta triển khai Dynamic Routes từng bước một.

Bước 1: Cài đặt React Router

Nếu chưa có, hãy thêm thư viện vào dự án của bạn:

npm install react-router-dom

Bước 2: Cấu hình Route động trong App.js

Trong file cấu hình routes chính, thường là App.js, bạn sử dụng dấu hai chấm : trước tên tham số để định nghĩa một route động.

// App.js
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
import HomePage from './pages/HomePage'
import ProductListPage from './pages/ProductListPage'
import ProductDetailPage from './pages/ProductDetailPage' // Component sẽ hiển thị chi tiết sản phẩm

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<HomePage />} />
        <Route path="/products" element={<ProductListPage />} />
        {/* Đây chính là Dynamic Route của chúng ta! */}
        <Route path="/products/:productId" element={<ProductDetailPage />} />
      </Routes>
    </Router>
  )
}

export default App

Trong ví dụ trên, :productId là một placeholder. Nó sẽ khớp với bất kỳ giá trị nào trong URL theo sau /products/, ví dụ /products/123 hay /products/abc.

Bước 3: Lấy tham số động với Hook useParams 🎣

Vậy làm thế nào để component ProductDetailPage biết được nó cần hiển thị sản phẩm nào? Chúng ta sẽ sử dụng hook useParams do React Router cung cấp.

useParams trả về một object chứa các cặp key/value của các tham số trên URL.

// pages/ProductDetailPage.js
import React from 'react'
import { useParams } from 'react-router-dom'

// Giả sử chúng ta có một mảng dữ liệu sản phẩm
const productsData = [
  { id: '1', name: 'iPhone 15 Pro', price: '25.000.000 VND' },
  { id: '2', name: 'Samsung Galaxy S25', price: '23.000.000 VND' },
  { id: '3', name: 'Google Pixel 9', price: '20.000.000 VND' },
]

function ProductDetailPage() {
  // Sử dụng useParams để lấy object params
  const params = useParams()
  const { productId } = params // Lấy ra productId từ object

  console.log('Product ID từ URL:', productId) // Sẽ in ra '1', '2', hoặc '3'...

  // Tìm sản phẩm trong mảng dữ liệu dựa trên productId
  const product = productsData.find((p) => p.id === productId)

  // Xử lý trường hợp không tìm thấy sản phẩm
  if (!product) {
    return <h2>Sản phẩm không tồn tại!</h2>
  }

  return (
    <div>
      <h1>Chi tiết sản phẩm</h1>
      <h2>{product.name}</h2>
      <p>Giá: {product.price}</p>
      <p>ID: {product.id}</p>
    </div>
  )
}

export default ProductDetailPage

Chỉ với vài dòng code, bạn đã có một trang chi tiết sản phẩm hoạt động hoàn hảo! Khi người dùng truy cập /products/1, useParams sẽ trả về { productId: '1' }. Component sẽ dùng ID này để tìm và hiển thị thông tin của "iPhone 15 Pro".

Mở rộng kiến thức: Các kịch bản nâng cao 🗺️

Nested Dynamic Routes (Route động lồng nhau)

Bạn hoàn toàn có thể lồng các route động vào nhau. Ví dụ, để xem các bài đánh giá cho một sản phẩm cụ thể: <Route path="/products/:productId/reviews/:reviewId" element={<ReviewDetail />} />

Trong component ReviewDetail, useParams sẽ trả về một object { productId: '...', reviewId: '...' }.

Điều hướng chương trình với useNavigate

Đôi khi bạn muốn chuyển hướng người dùng sau một hành động nào đó (ví dụ: sau khi họ tạo một sản phẩm mới). Hook useNavigate cho phép bạn làm điều này.

import { useNavigate } from 'react-router-dom'

function AddProductForm() {
  const navigate = useNavigate()

  const handleSubmit = (event) => {
    event.preventDefault()
    // Logic để thêm sản phẩm và nhận về ID của sản phẩm mới, ví dụ: newProductId = '4'
    const newProductId = '4'

    // Chuyển hướng người dùng đến trang chi tiết của sản phẩm vừa tạo
    navigate(`/products/${newProductId}`)
  }

  // ...
}

Kết luận: Dynamic Routes không phải tính năng phức tạp

Dynamic Routes không phải là một tính năng phức tạp, mà là một công cụ thiết yếu và thanh lịch trong bộ công cụ của mọi nhà phát triển React. Bằng cách nắm vững cách định nghĩa route với tham số :id và cách truy xuất các tham số đó bằng hook useParams, bạn đã mở ra khả năng xây dựng các ứng dụng web quy mô lớn, linh hoạt và mang lại trải nghiệm tuyệt vời cho người dùng.

Giờ thì, hãy bắt tay vào xây dựng những ứng dụng động tuyệt vời của riêng bạn!

Bài viết liên quan

[React Basics] Thuộc tính key trong React: Hiểu rõ và sử dụng hiệu quả

Bạn đã thực sự hiểu về thuộc tính key trong React? Tìm hiểu vai trò, cách dùng hiệu quả và các ví dụ thực tế giúp code của bạn sạch và tối ưu hơn.

[React Basics] Rendering Lists trong React: Cách làm chuẩn và tối ưu hiệu suất

Tìm hiểu các kỹ thuật render danh sách trong React, từ cơ bản với .map() đến các phương pháp nâng cao để xử lý dữ liệu động, tối ưu hiệu suất. Hướng dẫn này dành cho mọi cấp độ.

[React Basics] Hướng dẫn Testing trong React: Đảm bảo ứng dụng hoạt động hoàn hảo

Tìm hiểu về React testing, unit test và integration test trong bài viết chuyên sâu này. Nâng cao kỹ năng lập trình của bạn bằng cách học cách kiểm thử các React components một cách hiệu quả.

[React Basics] Khi nào nên dùng State Management trong ứng dụng React?

Bạn đang băn khoăn về việc sử dụng State Management trong dự án React? Bài viết này sẽ giúp bạn hiểu rõ các trường hợp cần và không cần, từ đó đưa ra lựa chọn tối ưu nhất.