Hướng Dẫn Sử Dụng Data APIs trong React Router v6.4
Giới thiệu
Phiên bản React Router v6.4 đã giới thiệu Data APIs — một nâng cấp quan trọng cho phép chúng ta xử lý lấy dữ liệu, biến đổi (hành động), và xử lý lỗi trực tiếp trong định nghĩa các route. Trong hướng dẫn này, chúng ta sẽ xây dựng một ứng dụng demo nhỏ sử dụng Vite + React Router + JSON Server.
Tại sao chọn React Router v6.4?
React Router là một thư viện quan trọng trong phát triển ứng dụng React, giúp quản lý điều hướng và trạng thái của ứng dụng. Với bản cập nhật này, React Router không chỉ dừng lại ở việc điều hướng mà còn mở rộng tới việc quản lý dữ liệu và giao diện.
Nội dung
- Giới thiệu về
createBrowserRouter - Cài đặt và cấu hình
- Thiết lập JSON Server
- Cấu trúc dự án
- Mã nguồn
- Cách hoạt động
- Chạy ứng dụng
- Kết luận
Giới thiệu về createBrowserRouter
createBrowserRouter là một hàm được giới thiệu trong React Router v6.4 như một phần của Data APIs mới. Nó:
- Định nghĩa tất cả các route trong một đối tượng cấu hình duy nhất.
- Hỗ trợ tải dữ liệu, xử lý lỗi và hành động.
- Thay thế cấu hình cũ
<BrowserRouter> + <Routes> + <Route>. - Phải kết hợp với
<RouterProvider>.
Điều này có nghĩa là routing hiện đã vượt xa điều hướng — nó còn liên quan đến dữ liệu + phối hợp giao diện.
Cài đặt và cấu hình
Để bắt đầu, chúng ta sẽ tạo một dự án mới bằng Vite:
bash
# Tạo dự án Vite
npm create vite@latest react-data-api-demo
cd react-data-api-demo
npm install
# Cài đặt các thư viện cần thiết
npm install react-router-dom
# Cài đặt JSON Server cho backend giả lập
npm install -g json-server
Thiết lập JSON Server
Tạo một tệp có tên db.json trong thư mục gốc của dự án:
json
{
"users": [
{
"id": "1",
"name": "Leanne Graham",
"email": "Sincere@april.biz"
},
{
"id": "2",
"name": "Ervin Howell",
"email": "Shanna@melissa.tv"
}
]
}
Chạy JSON Server:
bash
json-server --watch db.json --port 5000
Cấu trúc dự án
Dự án của chúng ta sẽ có cấu trúc như sau:
src/
├── App.jsx
├── main.jsx
├── router.js
├── pages/
│ ├── Users.jsx
│ ├── NewUserForm.jsx
│ └── ErrorPage.jsx
└── db.json
Mã nguồn
main.jsx
javascript
import { createRoot } from "react-dom/client";
import { RouterProvider } from "react-router-dom";
import router from "./router";
createRoot(document.getElementById("root")).render(
<RouterProvider router={router} />
);
router.js
javascript
import { createBrowserRouter } from "react-router-dom";
import App from "./App";
import ErrorPage from "./pages/ErrorPage";
import Users, { usersLoader } from "./pages/Users";
import NewUserForm, { addUserAction } from "./pages/NewUserForm";
const router = createBrowserRouter([
{
path: "/",
element: <App />,
errorElement: <ErrorPage />,
children: [
{
path: "users",
element: <Users />,
loader: usersLoader, // GET -> fetch users
},
{
path: "users/new",
element: <NewUserForm />,
action: addUserAction, // POST -> add user
},
],
},
]);
export default router;
App.jsx
javascript
import { NavLink, Outlet } from "react-router-dom";
const App = () => {
return (
<div style={{ padding: "20px" }}>
<h1>🚀 Ví dụ về Loader + Action của React Router</h1>
{/* Điều hướng */}
<nav style={{ marginBottom: "20px" }}>
<NavLink to="/" style={{ marginRight: "10px" }}>
Trang Chủ
</NavLink>
<NavLink to="/users" style={{ marginRight: "10px" }}>
Người Dùng
</NavLink>
<NavLink to="/users/new">Thêm Người Dùng</NavLink>
</nav>
{/* Nơi đây sẽ hiển thị các route con */}
<Outlet />
</div>
);
};
export default App;
pages/Users.jsx
javascript
import { useLoaderData, Link } from "react-router-dom";
export const usersLoader = async () => {
const response = await fetch("http://localhost:5000/users");
if (!response.ok) {
throw new Response("Lỗi khi tải người dùng", { status: response.status });
}
return response.json();
};
export default function Users() {
const users = useLoaderData();
return (
<div>
<h2>Danh Sách Người Dùng</h2>
<Link to="/users/new">➕ Thêm Người Dùng Mới</Link>
<ul>
{users.map((user) => (
<li key={user.id}>
{user.name} - {user.email}
</li>
))}
</ul>
</div>
);
}
pages/NewUserForm.jsx
javascript
import { Form, redirect } from "react-router-dom";
export const addUserAction = async ({ request }) => {
const formData = await request.formData();
const newUser = {
name: formData.get("name"),
email: formData.get("email"),
};
// Giả lập yêu cầu POST
const response = await fetch("http://localhost:5000/users", {
method: "POST",
body: JSON.stringify(newUser),
headers: { "Content-Type": "application/json" },
});
if (!response.ok) {
throw new Response("Lỗi khi thêm người dùng", { status: response.status });
}
// Sau khi thành công -> chuyển hướng về danh sách người dùng
return redirect("/users");
};
const NewUserForm = () => {
return (
<div>
<h2>Thêm Người Dùng Mới</h2>
<Form method="post">
<input
type="text"
name="name"
id="name"
placeholder="Tên"
required
/>
<input
type="email"
name="email"
id="email"
placeholder="Email"
required
/>
<button type="submit">Lưu</button>
</Form>
</div>
);
};
export default NewUserForm;
pages/ErrorPage.jsx
javascript
import { useRouteError } from "react-router-dom";
const ErrorPage = () => {
const error = useRouteError();
return (
<div style={{ padding: "20px", color: "red" }}>
<h2>⚠ Oops! Đã có lỗi xảy ra</h2>
<p>{error.statusText || error.message}</p>
</div>
);
};
export default ErrorPage;
Cách hoạt động
- Truy cập
/users→ Loader chạy → Lấy danh sách người dùng → Hiển thị danh sách. - Nhấn Thêm Người Dùng Mới → Điều hướng đến
/users/new. - Điền thông tin → Action chạy → Gửi yêu cầu POST.
- Khi thành công → Chuyển hướng về
/usersvới dữ liệu cập nhật. - Khi có lỗi → ErrorPage hiển thị lỗi.
Chạy ứng dụng
Để chạy ứng dụng, chúng ta cần khởi động cả JSON Server và Vite:
bash
# Khởi động JSON Server
json-server --watch db.json --port 5000
# Khởi động Vite
npm run dev
Bây giờ mở trình duyệt và truy cập http://localhost:5173/users 🎉
Kết luận
Với Data APIs trong React Router v6.4, việc lấy dữ liệu và gửi biểu mẫu trở nên có cấu trúc và tuyên bố hơn. Kết hợp với Vite và JSON Server, bạn có thể dễ dàng thử nghiệm và xây dựng các demo nhỏ.
👉 Nếu bạn đang học React, hãy thử thiết lập này và khám phá cách mà loaders, actions và boundaries xử lý lỗi giúp đơn giản hóa việc quản lý dữ liệu!