Giả sử ứng dụng hiện đang có các route sau:

<Route path="/" element={<Home />} />
<Route path="/books" element={<BookList />} />

Dynamic Routes

Trong trường hợp ta muốn thiết lập route cho từng quyển sách, chẳng hạn như /books/1 hay /books/2, ta cần dùng dynamic route như sau:

<Route path="/books/:id" element={<Book />} />

Với component Book có dạng như sau:

function Book() {
  return <h1>Book</h1>
}

Bất kỳ đường dẫn nào có dạng /books/:id, với :id là chuỗi ký tự bất kỳ, đều sẽ match với route trên.

Info

Trong trường hợp ta định nghĩa một route với đường dẫn được gán cứng, chẳng hạn /books/new thì React Router sẽ không match đường dẫn này với route /books/:id.

Để lấy giá trị 1 hay 2 từ đường dẫn và hiển thị nó ở trong từng component Book, ta cần dùng hook useParams của React Router như sau:

import { useParams } from "react-router-dom"
 
function Book() {
  const { id } = useParams()
  return <h1>Book {id}</h1>
}

Nested Routes

Giả sử ta có các route sau:

<Route path="/books" element={<BookList />} />
<Route path="/books/:id" element={<Book />} />
<Route path="/books/new" element={<NewBook />} />

Chúng ta có thể dùng các route lồng nhau như sau:

<Route path="/books">
  <Route path=":id" element={<Book />} />
  <Route path="new" element={<NewBook />} />
</Route>

Để render ra component BookList tương ứng với đường dẫn /books, ta cần thêm vào một route có props index như sau:

<Route path="/books">
  <Route index element={<BookList />} />
  <Route path=":id" element={<Book />} />
  <Route path="new" element={<NewBook />} />
</Route>

Layout

Giả sử ta có các liên kết đến các route của /books như sau:

<ul>
  <li>
    <Link to="/books/1">Book 1</Link>
  </li>
  <li>
    <Link to="/books/2">Book 2</Link>
  </li>
  <li>
    <Link to="/books/new">New Book</Link>
  </li>
</ul>

Để thêm các liên kết này vào các component thuộc các route của /books, ta có thể cho chúng vào một layout component, chẳng hạn BookLayout:

import { Link, Outlet } from "react-router-dom"
 
function BookLayout() {
  return (
    <>
      <ul>
        <li>
          <Link to="/books/1">Book 1</Link>
        </li>
        <li>
          <Link to="/books/2">Book 2</Link>
        </li>
        <li>
          <Link to="/books/new">New Book</Link>
        </li>
      </ul>
      <Outlet />
    </>
  )
}

Important

Lưu ý là ta cần phải gọi component Outlet để chỉ định vị trí mà child route được render.

Sau đó gọi sử dụng layout này ở route /books:

<Route path="/books" element={<BookLayout />}>
  <Route index element={<BookList />} />
  <Route path=":id" element={<Book />} />
  <Route path="new" element={<NewBook />} />
</Route>

Bằng cách này, các child route của /books sẽ luôn có một danh sách các liên kết đi kèm.

Context

Ở trong component Outlet, ta có thể truyền dữ liệu cho các child route thông qua một props có tên là context như sau:

<Outlet context={{ saleOff: 50 }}

Lấy ra context ở trong các component thuộc các child route bằng cách dùng hook useOutletContext như sau:

import { useOutletContext } from "react"
 
function Book() {
  const context = useOutletContext()
  return (
    <h1>
      Book {id} (Sale off: {context.saleOff}%)
    </h1>
  )
}

Routes Component

Ta có thể tách các route thành một component riêng:

function BookRoutes() {
  return (
    <Routes>
      <Route element={<BookLayout />}>
        <Route index element={<BookList />} />
        <Route path=":id" element={<Book />} />
        <Route path="new" element={<NewBook />} />
      </Route>
    </Routes>
  )
}

Và dùng component đó ở route /books như sau:

<Route path="/books/*" element={<BookRoutes />} />

Lưu ý là ta cần thêm vào path chuỗi /*.

useRoutes

Thay vì dùng component RoutesRoute để thiết lập các route của ứng dụng, ta có thể sử dụng hook useRoutes như sau:

const Routes = useRoutes([
  {
    path: "/",
    element: <Home />,
  },
  {
    path: "/books/*",
    element: <BookRoutes />,
  },
  {
    path: "*",
    element: <NotFound />,
  },
])

Gọi sử dụng như là một JSX element:

function App() {
  return (
    // ...
    { Routes }
  )
}

Resources