路由,记录组件和路径的映射关系。后监听路径,当路径发生改变时,渲染相应的组件。
基本映射
一、全局挂载元素使用react-router
import {
createBrowserRouter,
RouterProvider,
} from "react-router-dom";
ReactDOM.createRoot(document.getElementById("root")).render(
<RouterProvider router={router} />
);
二、配置映射关系
(一)、组件式映射关系
const router = createBrowserRouter(
createRoutesFromElements(
<>
<Route path="/" element={<Root />}>
<Route path="child1" element={<Child1 />} />
<Route path="child2" element={<Child2 />} />
</Route>
<Route path="/place" element={<Place />}>
<Route path="/place/area1" element={<Area1 />} />
<Route path="/place/area2" element={<Area2 />} />
</Route>
)
);
(二)、配置式映射关系
const router = createBrowserRouter([
{
path: "/",
element: <Root />,
children: [
{
path: "child1",
element: <Child1 />,
},
{
path: "child2",
element: <Child2 />,
},
],
},
{
element: <AuthLayout />,
children: [
{
path: "login",
element: <Login />,
loader: redirectIfUser,
},
{
path: "logout",
action: logoutUser,
},
],
},
]);
三、嵌套路由
配置嵌套路由关系:
(一)、组件式
// Configure nested routes with JSX
createBrowserRouter(
createRoutesFromElements(
<Route path="/" element={<Root />}>
<Route path="contact" element={<Contact />} />
<Route
path="dashboard"
element={<Dashboard />}
loader={({ request }) =>
fetch("/api/dashboard.json", {
signal: request.signal,
})
}
/>
<Route element={<AuthLayout />}>
<Route
path="login"
element={<Login />}
loader={redirectIfUser}
/>
<Route path="logout" />
</Route>
</Route>
)
);
(二)、配置式
createBrowserRouter([
{
path: "/",
element: <Root />,
children: [
{
path: "contact",
element: <Contact />,
},
{
path: "dashboard",
element: <Dashboard />,
loader: ({ request }) =>
fetch("/api/dashboard.json", {
signal: request.signal,
}),
},
{
element: <AuthLayout />,
children: [
{
path: "login",
element: <Login />,
loader: redirectIfUser,
},
{
path: "logout",
action: logoutUser,
},
],
},
],
},
]);
【注】在父路由组件中配置Outlet进行决定子路由组件渲染在父路由组件的哪个位置
import { Outlet } from "react-router-dom";
export default function Root() {
return (
<>
{/* all the other elements */}
<div id="detail">
<Outlet />
</div>
</>
);
}
传参
params传参
<Route path="projects/:projectId/tasks/:taskId" />
function Task() {
// returned from `useParams`
const params = useParams();
params.projectId; // abc
params.taskId; // 3
}
function Random() {
const match = useMatch("/projects/:projectId/tasks/3");
match.params.projectId; // abc
match.params.taskId; // 3
}
query传参
const [searchParams] = useSearchParams()
console.log('searchParams', Object.fromEntries(searchParams))
跳转
组件跳转
<NavLink />比<Link />多了isActive 、isPending参数来表示当前路由是否是激活状态。
<NavLink
style={({ isActive, isPending }) => {
return {
color: isActive ? "red" : "inherit",
};
}}
className={({ isActive, isPending }) => {
return isActive ? "active" : isPending ? "pending" : "";
}}
/>
<Link
style={({ isActive, isPending }) => {
return {
color: isActive ? "red" : "inherit",
};
}}
className={({ isActive, isPending }) => {
return isActive ? "active" : isPending ? "pending" : "";
}}
/>
编程式跳转
import { useNavigate } from "react-router-dom";
function useLogoutTimer() {
const userIsInactive = useFakeInactiveUser();
const navigate = useNavigate();
useEffect(() => {
if (userIsInactive) {
fake.logout();
navigate("/session-timed-out");
}
}, [userIsInactive]);
}
错误页面
const router = createBrowserRouter([
{
path: "/",
element: <div>Hello world!</div>,
errorElement: <ErrorPage />,
},
]);
// 查看错误信息
import { useRouteError } from "react-router-dom";
export default function ErrorPage() {
const error = useRouteError();
console.error(error);
return (
<div id="error-page">
<h1>Oops!</h1>
<p>Sorry, an unexpected error has occurred.</p>
<p>
<i>{error.statusText || error.message}</i>
</p>
</div>