Ứng dụng trang đơn (Single Page Applications) đã tạo nên một cuộc cách mạng trong lĩnh vực phát triển web. Chúng mang đến trải nghiệm người dùng linh hoạt và năng động hơn so với các ứng dụng đa trang truyền thống. Các ứng dụng web truyền thống yêu cầu tải lại toàn bộ trang cho hầu hết mọi thao tác nhấp chuột của người dùng. Mặt khác, SPA chỉ tải một trang HTML duy nhất và cập nhật nội dung trang một cách linh hoạt khi người dùng tương tác với ứng dụng. Sự linh hoạt này mang lại cảm giác như đang sử dụng ứng dụng desktop và cho ra kết quả tương tác nhạy bén hơn.
Để theo kịp những gì bài viết này đề cập, bạn nên có kiến thức cơ bản về React và cách thiết lập một dự án React. Nếu bạn đã có đầy đủ kiến thức, hãy cùng bắt đầu nhé.
React Router và React Router DOM là gì?
React Router là một thư viện mạnh mẽ quản lý điều hướng và định tuyến trong các ứng dụng React. React Router DOM được sử dụng dành riêng cho các ứng dụng web và có một số API dành riêng cho DOM.
Khi chúng ta đi sâu vào thế giới của React Router DOM, chúng ta sẽ khám phá các khái niệm cốt lõi của nó đồng thời trình bày việc triển khai chúng trong một ứng dụng React. Trọng tâm của chúng ta sẽ là xây dựng một hệ thống điều hướng đơn giản với các liên kết đến các thành phần khác nhau, minh họa cách định cấu hình các tuyến đường, xử lý khớp tuyến đường và triển khai điều hướng.
Vào cuối bài viết này, bạn sẽ có kiến thức vững chắc về cách sử dụng React Router DOM để tạo trải nghiệm điều hướng liền mạch và linh hoạt trong các ứng dụng trang đơn của mình.
Cách cài đặt React Router
Như đã giải thích ở trên, React-router-DOM được sử dụng riêng để tích hợp chức năng định tuyến vào các ứng dụng web. Vì vậy, để sử dụng nó trong ứng dụng React của bạn, bạn cần cài đặt gói react-router-dom bằng cách chạy lệnh này trong thiết bị đầu cuối ứng dụng React của bạn:
npm install react-router-dom
Sau khi cài đặt thành công, bạn có thể bắt đầu định tuyến trong dự án React của mình.
Các khái niệm cốt lõi trong React Router DOM
1. BrowserRouter
BrowserRouter là một thành phần cha chứa tất cả các thành phần tuyến đường. Tất cả các tuyến đường mà bạn sử dụng trong một ứng dụng phải được khai báo trong BrowserRouter. Quan trọng nhất, nó lưu trữ vị trí hiện tại trong thanh địa chỉ của trình duyệt bằng cách sử dụng URL, điều này rất hữu ích trong quá trình điều hướng.
Để sử dụng BrowserRouter, bạn cần nhập nó từ react-router-dom trong tệp App.jsx của bạn.
import { BrowserRouter } from "react-router-dom"; function App() { return ( <BrowserRouter> </BrowserRouter> );
} export default App;
BrowserRouter có thuộc tính basename được sử dụng để đặt URL cơ sở cho tất cả các tuyến đường trong một ứng dụng. Điều này rất quan trọng nếu ứng dụng của bạn được lưu trữ trong một thư mục con trên một tên miền.
<BrowserRouter basename="/shop"> </BrowserRouter>
Việc thêm /shop làm basename sẽ đảm bảo rằng tất cả các đường dẫn tuyến đường đều tương đối với /shop.
2. Routes
Thành phần này là sự thay thế trực tiếp cho switch được sử dụng trong các phiên bản trước của React Router. Nó cũng hoạt động giống như một thành phần cha và hiển thị routes con phù hợp đầu tiên, đảm bảo rằng thành phần chính xác được hiển thị dựa trên URL hiện tại.
Để khai báo các routes, hãy nhập routes từ react-router-dom và đặt nó trong thành phần BrowserRouter.
import { BrowserRouter, routes } from "react-router-dom"; function App() { return ( <BrowserRouter> <Routes> </Routes> </BrowserRouter> );
} export default App;
3. Route
Route là một thành phần con bao gồm hai thuộc tính: path và element. path có thể là bất kỳ tên đường dẫn nào được chỉ định trong khi thuộc tính element là thành phần cần được hiển thị. Một tuyến đường hiển thị một thành phần cụ thể khi đường dẫn được chỉ định khớp với URL.
Một ứng dụng có thể có bao nhiêu route tùy ý và tất cả chúng phải được khai báo bên trong thành phần Routes. Giả sử chúng ta có thành phần <Home> và <Pricing>, chúng ta sẽ phải nhập thành phần Route và đặt nó trong Routes.
import { BrowserRouter, Routes, Route } from "react-router-dom"; //ALL COMPONENTS IMPORTS COMES HERE function App() { return ( <BrowserRouter> <Routes> <Route path="/" element={<Home/>}/> <Route path="pricing" element={<Pricing/>}/> </Routes> </BrowserRouter> );
} export default App;
4. Undeclared Routes
Có một cách để xử lý các Route không tồn tại trong ứng dụng của bạn, giống như trang Lỗi 404. Để làm điều này, hãy tạo một thành phần khác mang thông báo Không Tìm Thấy và thêm route.
Đặt tên đường dẫn thành * và chuyển thành phần làm element.
import { BrowserRouter, Routes, Route } from "react-router-dom"; //ALL COMPONENTS IMPORTS COMES HERE function App() { return ( <BrowserRouter> <Routes> <Route path="/" element={<Home/>}/> <Route path="pricing" element={<Pricing/>}/> <Route path="*" element={<PageNotFound/>}/> </Routes> </BrowserRouter> );
} export default App;
5. Nested Routes
Trong một số trường hợp, các routes có thể có tuyến con hoặc sub-routes.
import { BrowserRouter, Routes, Route } from "react-router-dom"; //ALL COMPONENTS IMPORTS COMES HERE function App() { return ( <BrowserRouter> <Routes> <Route path="/" element={<Home/>}/> <Route path="pricing" element={<Pricing/>}/> <Route path="categories" element={<Categories/>}> <Route path="male" element={<Male/>}/> <Route path="female" element={<Female/>}/> </Route> <Route path="*" element={<PageNotFound/>}/> </Routes> </BrowserRouter> );
} export default App;
Khi điều hướng đến các phần tử lồng nhau, URL trên trình duyệt sẽ hiển thị như /categories/male và /categories/female.
6. Link
Nó hoạt động giống như thuộc tính anchor href. Nó có thuộc tính to chỉ định nơi Link sẽ đưa người dùng đến sau khi nhấp vào. Thông thường, đường dẫn đến trang của thành phần được truyền cho thuộc tính to.
Các liên kết thường được đặt trong thành phần Navbar, vì vậy chúng ta sẽ đặt hai liên kết trỏ đến đường dẫn của thành phần trong Routes đã khai báo của chúng ta.
import { Link } from "react-router-dom";
export default function PageNav() { return ( <> <Link to="/">Home</Link> <Link to="pricing">Pricing</Link> </> );
}
Lưu ý: Nếu bạn đang thực hành trong khi đọc bài viết này, điều quan trọng cần lưu ý là thành phần PageNav được tạo ở đây nên được đặt trong tệp App.jsx của bạn và cụ thể là ngay sau thẻ BrowserRouter mở trước Routes. Điều này là để đảm bảo PageNav luôn ở trên cùng như một menu điều hướng mặc dù định tuyến qua các thành phần khác nhau.
import { BrowserRouter, Routes, Route } from "react-router-dom"; //ALL COMPONENTS IMPORTS COMES HERE function App() { return ( <BrowserRouter> <PageNav/> <Routes> <Route path="/" element={<Home/>}/> <Route path="pricing" element={<Pricing/>}/> <Route path="categories" element={<Categories/>}> <Route path="male" element={<Male/>}/> <Route path="female" element={<Female/>}/> </Route> <Route path="*" element={<PageNotFound/>}/> </Routes> </BrowserRouter> );
} export default App;
7. NavLink
NavLink thực hiện chức năng tương tự như Link và cũng có thuộc tính to. Nhưng nó khác ở chỗ nó có thuộc tính class. Các thuộc tính class là active, isPending và isTransitioning. Điều này làm cho nó linh hoạt hơn Link và bạn có thể sử dụng nó để thêm kiểu có điều kiện trong quá trình tương tác của người dùng.
import { NavLink } from "react-router-dom";
export default function PageNav() { return ( <> <NavLink to="/">Home</NavLink> <NavLink to="pricing">Pricing</NavLink> </> ); }
8. Outlet
Việc có các phần tử con bên trong phần tử tuyến đường cha nghĩa là có một lớp trừu tượng trong việc hiển thị UI của tuyến đường con. Đây là lúc thành phần Outlet phát huy tác dụng. Bạn thêm nó vào tuyến đường cha – trong ví dụ của chúng ta, đó sẽ là thành phần Categories.
import { NavLink, Outlet } from "react-router-dom";
export default function Categories() { return ( <> <NavLink to="men"> Men </NavLink> <NavLink to="women"> Women </NavLink> <Outlet />
</> );
}
Điều này cho phép hiển thị UI của tuyến đường con trong tuyến đường lồng nhau.
9. Hook useNavigate
Hook này trả về một hàm cho phép điều hướng theo chương trình giữa các tuyến đường.
Có một số cách để sử dụng hàm điều hướng trong ứng dụng của bạn. Đầu tiên, chúng ta cần nhập hook useNavigate và khởi tạo nó là navigate.
import { useNavigate } from "react-router-dom"; export default function Homepage() { const navigate = useNavigate(); return ( <> <h1>This is the Homepage</h1> </> );
}
Chúng ta có thể sử dụng navigate theo các cách sau trong ứng dụng của mình:
- Gắn nó vào một nút thông qua thuộc tính onClick với đường dẫn dự định được điều hướng đến, được truyền cho hàm navigate.
<button onClick={() => navigate("/categories")}>Go to Categories</button>
- Sử dụng nó với thành phần Link.
<Link to={navigate("/categories")}>Go to Categories</Link>
- Sử dụng một số thay vì đường dẫn thành phần trong hàm navigate. Số này phải chỉ định số lần điều hướng ngược trong ngăn xếp lịch sử mà bạn muốn đến.
<Link to={navigate(-1)}>Go one step backwards</Link>
11. Hook useParams
Trả về một đối tượng của params động nhận được từ URL hiện tại được khớp bởi đường dẫn của Route. Các tuyến đường cha chuyển tất cả params cho các tuyến đường con của chúng.
Ví dụ bên dưới cho thấy thành phần OrderPage sẽ được hiển thị cho mọi customer với id duy nhất của họ. Khi URL khớp với /customer/123, :id sẽ là 123.
import { useParams } from "react-router-dom"; function App() { const {id} = useParams() return ( <BrowserRouter> <Routes> <Route path="customer"> <Route path=":id" element={<OrderPage/>}/> </Route> </Routes> </BrowserRouter> );
} export default App;
Tại thời điểm này, chúng ta đã triển khai đầy đủ React Router trong dự án điều hướng nhỏ của mình.
Để biết thêm thông tin chi tiết và các khái niệm về React Router, bạn có thể truy cập trang tài liệu chính thức của React Router.
Kết luận
Trong bài viết này, chúng ta đã khám phá các khái niệm và triển khai Client Side Routing (CSR) trong ứng dụng web React. React Router, thông qua thư viện React-Router-DOM dành cho web của nó, cho phép CSR, cho phép các ứng dụng cập nhật URL bằng một cú nhấp chuột vào liên kết mà không cần yêu cầu máy chủ cho một tài liệu mới.
Chức năng này nâng cao trải nghiệm người dùng bằng cách cung cấp điều hướng nhanh hơn và tương tác liền mạch hơn trong ứng dụng. Bằng cách tận dụng CSR, các nhà phát triển có thể xây dựng các ứng dụng trang đơn (SPA) hiệu quả và phản hồi nhanh hơn, từ đó cải thiện hiệu suất và sự hài lòng của người dùng.
Cảm ơn các bạn đã theo dõi.