1. 路由
1.1 路由渲染
一般路由的使用流程
/src/routes/index.js
import { Navigate } from 'react-router-dom'
import About from '../components/About'
import Home from '../components/Home'
const routes = [{
path: '/about',
element: <About /> },
{
path: '/home',
element: <Home /> },
{
path: '/',
element: <Navigate to='/about' /> }
]
export default routes
App.js
import React from "react";
import { NavLink, useRoutes } from "react-router-dom"; //引入
import routes from "./routes";
export default function App() {
const elements = useRoutes(routes) //初始化
return (
<div>
{/* 注册路由 */}
{elements}
</div>
)
● 嵌套路由
/src/routes/index.js
子路由 NavLink 的 to 可以像原来一样写全 path:to="/home/news"
也可以直接 ./ + 子路由名:to="./news"
最简单直接写子路由名:to="news"
子路由组件呈现的位置直接使用 6 提供的 标签声明即可,会自动分配子路由管理
/Home/index.js
react router6 (vite创建react项目,实际项目使用)
使用 createBrowserRouter,RouterProvider
// src/routes/index.js
import React from "react"
// AliveScope:react 实现keep-alive功能。将渲染过的组件(div.ka-content)存起来,等到再次用,从缓存拿到,使用js的 appendchild 到 KeepAlive中的 (div.ka-wrapper)
import { AliveScope } from "react-activation";
import { Navigate } from "react-router-dom";
import Layout from "../layouts";
import HomePage from "../pages/HomePage";
import Backlog from "../pages/Backlog";
import Personal from "../pages/Profile/Personal";
import Changepwd from "../pages/Profile/Changepwd";
export const rootRouter: any = [
{
path: "/",
exact: true,
element: (
<AliveScope>
<Layout />
</AliveScope>
),
children: [
{ path: "", element: <Navigate to="/homepage" /> },
{
path: "/homepage",
exact: true,
element: <HomePage />,
},
{
path: "/backlog",
exact: true,
element: <Backlog />,
},
{
path: "/profile/personal",
exact: true,
element: <Personal />,
},
{
path: "/profile/changepwd",
exact: true,
element: <Changepwd />,
},
],
},
];
// src/container/App.tsx
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import { rootRouter } from "../routers";
function App() {
const element = createBrowserRouter(rootRouter);
return (
<>
<RouterProvider router={element} />
</>
);
}
export default App;
// src/container/Main.tsx
import { observer } from "mobx-react";
import { App as AntdApp, ConfigProvider, theme } from "antd";
import zhCN from "antd/locale/zh_CN";
import App from "./App.tsx";
function Main() {
return (
<ConfigProvider
locale={zhCN}
prefixCls=""
theme={{
// algorithm: theme.defaultAlgorithm,
// token: {
// colorPrimary: "#00b96b",
// borderRadius: 2,
// },
components: {
Button: {
colorPrimary: "pink",
},
},
}}
>
<AntdApp>
<App />
</AntdApp>
</ConfigProvider>
);
}
export default observer(Main);
// src/container/Root.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.tsx";
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
// index.html
<body>
<div id="root"></div>
<script type="module" src="/src/container/Root.tsx"></script>
</body>
// src/layouts/index.tsx
import React from "react";
import { Outlet, useNavigate } from "react-router-dom";
import {
UserOutlined,
DesktopOutlined,
PieChartOutlined,
} from "@ant-design/icons";
import type { MenuProps } from "antd";
import { Breadcrumb, Layout, Menu, theme } from "antd";
const { Header, Content, Footer, Sider } = Layout;
type MenuItem = Required<MenuProps>["items"][number];
function getItem(
label: React.ReactNode,
key: React.Key,
icon?: React.ReactNode,
children?: MenuItem[]
): MenuItem {
return {
key,
icon,
children,
label,
} as MenuItem;
}
const items1: MenuItem[] = [
getItem("首页", "homepage", <PieChartOutlined />),
getItem("待办", "backlog", <DesktopOutlined />),
getItem("用户设置", "profile", <UserOutlined />, [
getItem("人员列表", "/profile/list"),
getItem("个人信息", "/profile/personal1"),
getItem("修改密码", "/profile/changepwd"),
]),
getItem("模块案例", "case", <UserOutlined />, [
getItem("接口请求方法", "/case/interfaceRequest"),
]),
];
const App: React.FC = () => {
const navigate = useNavigate();
const {
token: { colorBgContainer },
} = theme.useToken();
const onClick: MenuProps["onClick"] = (menuItem) => {
console.log("click ", menuItem);
const { key }: any = menuItem;
navigate(key);
};
return (
<Layout style={{ minHeight: "100vh" }}>
<Header style={{ display: "flex", alignItems: "center" }}>
<span style={{ color: "#fff", fontSize: "20px", textAlign: "center" }}>
后台管理系统
</span>
</Header>
<Layout>
<Sider width={200} collapsible style={{ background: colorBgContainer }}>
<Menu
mode="inline"
theme="light"
defaultSelectedKeys={["homepage"]}
defaultOpenKeys={["sub1"]}
style={{ height: "100%", borderRight: 0 }}
items={items1}
onClick={onClick}
/>
</Sider>
<Layout style={{ padding: "0 24px 24px" }}>
<Breadcrumb
style={{ margin: "16px 0" }}
items={[
{
title: "Home",
},
{
title: <a href="">Application Center</a>,
},
{
title: <a href="">Application List</a>,
},
{
title: "An Application",
},
]}
/>
<Content
style={{
padding: 24,
margin: 0,
minHeight: 600,
background: colorBgContainer,
}}
>
<Outlet /> // 重点!!!
</Content>
<Footer style={{ textAlign: "center", padding: "6px " }}>
Ant Design ©2023 Created by Ant UED
</Footer>
</Layout>
</Layout>
</Layout>
);
};
export default App;
1.2 路由跳转
1. dom标签
通过 Link/NavLink 传值跳转:
import { Link } from "react-router-dom";
const Home = () => {
return (
<div>
<h1>你好很</h1>
<Link to="/test1">跳转test1</Link>
</div>
);
};
export default Home;
2. js
使用 useNavigate 跳转页面:
// test.jsx
import { useNavigate } from "react-router-dom";
const Test = () => {
const navigate = useNavigate();
const toTest2 = () => {
navigate("/test2?name=tom&age=18", {
state: "linjing",
}); // search传参
// navigate("/test2", {
// state: [{ code: "linjing", id: 10 }],
// }); // state 传参
};
return <div onClick={toTest2}>跳转测试页面2</div>;
};
export default Test;
// /Home/index.jsx
// 总结三种跳转方式
import { observer } from "mobx-react";
import { NavLink, Link, useNavigate } from "react-router-dom";
import { Button, Divider } from "antd";
const HomePage = () => {
const navigate = useNavigate();
const handleClick = () => {
navigate("/case/interfaceRequest");
};
return (
<>
<div>
<NavLink to="/case/interfaceRequest">案例 NavLink</NavLink>
<Divider />
<Link to="/case/interfaceRequest">跳转 Link</Link>
<Divider />
<Button type="link" onClick={handleClick}>
跳转案例 onClick
</Button>
</div>
</>
);
};
export default observer(HomePage);
1.3 传参方式
1.params传参
优点:刷新页面,参数不丢失。
缺点:1.只能传字符串,传值过多url会变得很长。 2.参数必须在路由上配置
// 配置 src/routers/index.jsx
{
path: "/case/interfaceRequest/:id/:name",
exact: true,
element: <InterfaceRequest />,
},
// 路由跳转与获取路由参数 src/HomePage/index.jsx
import {useNavigate } from "react-router-dom";
const navigate = useNavigate();
// 跳转路由 地址栏:/detail/2/linjing
navigate("/case/interfaceRequest/2/linjing");
// 获取路由参数
const params = useParams()
console.log(params) // {id: "2",name:"linjing"}
2.search 传参
优点:刷新页面,参数不丢失。
缺点:1.只能传字符串,传值过多url会变得很长。 2.获取参数需要自定义hooks
// 配置 src/routers/index.jsx
{ path: '/detail', component: Detail }
// 路由跳转与获取路由参数 src/HomePage/index.jsx
import {useNavigate } from "react-router-dom";
const navigate = useNavigate();
// 跳转路由 地址栏:?id=2&name=%27linjing%27
navigate("/case/interfaceRequest?id=2&name='linjing'"); // search
// 获取参数
const getUrlData = () => {
const urlArr = window.location.href.split("?")[1].split("&");
console.log("urlArr: ", urlArr);
const obj: any = {};
urlArr.forEach((item) => {
console.log("item: ", item);
const name = item.substring(0, item.indexOf("="));
console.log("name: ", name);
let value = item.substring(item.indexOf("=") + 1);
console.log("value: ", value);
value = decodeURIComponent(value); // 解码由 encodeURIComponent 方法或者其他类似方法编码的部分统一资源标识符(URI)
obj[name] = value;
});
return obj;
};
const params = getUrlData();
console.log("params: ", params);
3.state 传参
优点:可以传对象。
缺点:<HashRouter>刷新页面,参数丢失
// 配置 src/routers/index.jsx
{ path: '/detail', element: <Detail/> }
// 路由跳转与获取路由参数 src/HomePage/index.jsx
import { useNavigate } from 'react-router-dom';
// 路由跳转
const item = { id: 10, name: "linjing" };
navigate("/case/interfaceRequest", { state: item }); // state
// 参数获取
import { useLocation } from 'react-router-dom';
const {state} = useLocation()
console.log(state) // {id:10,name:"linjing"}
<HashRouter> 不支持 location.key 与 location.state,<HashRouter>通过state传递参数,刷新页面后参数丢失,官方建议使用<BrowserRouter>,<BrowserRouter>页面刷新参数也不会丢失
总结:不同的路由传参一定要注意,是否要在注册路由的时候接收,一定要使用对应的hook接收对应的参数。