React 基础巩固(四十一)------手动路由跳转、参数传递及路由配置
一、实现手动跳转路由
- 利用 useNavigate 封装一个 withRouter(hoc/with_router.js)
javascript
import { useNavigate } from "react-router-dom";
// 封装一个高阶组件
function withRouter(WrapperComponent) {
return function (props) {
const navigate = useNavigate();
const router = { navigate };
return <WrapperComponent {...props} router={router} />;
};
}
export default withRouter;
- 添加到hoc/index.js文件中
javascript
import withRouter from "./with_router";
export { withRouter };
- 利用withRouter,拦截Home组件,实现手动跳转路由
javascript
import React, { PureComponent } from "react";
import { Link, Outlet } from "react-router-dom";
import { withRouter } from "../hoc";
export class Home extends PureComponent {
navigateTo(path) {
const { navigate } = this.props.router;
navigate(path);
}
render() {
return (
<div>
<h1>Home</h1>
<div className="nav">
<Link to="/home/recommend">推荐</Link>
<Link to="/home/ranking">排行榜</Link>
<button onClick={(e) => this.navigateTo("/home/songmenu")}>
歌单
</button>
</div>
{/* 占位组件 */}
<Outlet />
</div>
);
}
}
export default withRouter(Home);
二、路由参数传递
路由参数传递包括:1.动态路由传参;2.查询字符串传参
改造withRouter,通过useParams()
和useSearchParams()
来接收两种参数传递:
javascript
import {
useLocation,
useNavigate,
useParams,
useSearchParams,
} from "react-router-dom";
// 封装一个高阶组件
function withRouter(WrapperComponent) {
return function (props) {
// 1.导航
const navigate = useNavigate();
// 2.动态路由参数
const params = useParams();
// 3.查询字符串的参数:/user?name=test&age=18
const location = useLocation();
const [searchParams] = useSearchParams();
const query = Object.fromEntries(searchParams)
console.log(query);
const router = { navigate, params, location, query };
return <WrapperComponent {...props} router={router} />;
};
}
export default withRouter;
在界面中,通过params来接收(Detail.js):
javascript
import React, { PureComponent } from "react";
import { withRouter } from "../hoc";
export class Detail extends PureComponent {
render() {
const { router } = this.props;
const { params } = router;
return (
<div>
<h2>Detail</h2>
<h2>id:{params.id}</h2>
</div>
);
}
}
export default withRouter(Detail);
通过 query 来接收(User.jsx):
javascript
import React, { PureComponent } from "react";
import { withRouter } from "../hoc";
export class User extends PureComponent {
render() {
const { router } = this.props;
const { query } = router;
return (
<div>
<h1>
用户:{query.name} - {query.age}
</h1>
</div>
);
}
}
export default withRouter(User);
三、路由配置文件
当前App.jsx文件中,包含Routes相关信息,过于臃肿,我们可以将Routes通过配置的形式进行引入。
构建router/index.js,将所有的路由配置在此处:
javascript
import Home from "../pages/Home";
import About from "../pages/About";
import Login from "../pages/Login";
import NotFound from "../pages/NotFound";
import HomeRecommend from "../pages/HomeRecommend";
import HomeRanking from "../pages/HomeRanking";
import Category from "../pages/Category";
import Order from "../pages/Order";
import HomeSangMenu from "../pages/HomeSangMenu";
import Detail from "../pages/Detail";
import User from "../pages/User";
import { Navigate } from "react-router-dom";
const routes = [
{
path: "/",
element: <Navigate to="/home" />,
},
{
path: "/home",
element: <Home />,
children: [
{
path: "/home",
element: <Navigate to="/home/recommend" />,
},
{
path: "/home/recommend",
element: <HomeRecommend />,
},
{
path: "/home/ranking",
element: <HomeRanking />,
},
{
path: "/home/sangmenu",
element: <HomeSangMenu />,
},
],
},
{
path: "/about",
element: <About />,
},
{
path: "/login",
element: <Login />,
},
{
path: "/category",
element: <Category />,
},
{
path: "/order",
element: <Order />,
},
{
path: "/detail",
element: <Detail />,
},
{
path: "/user",
element: <User />,
},
{
path: "*",
element: <NotFound />,
},
];
export default routes;
改写App.jsx,通过useRoutes(routes)
引入路由:
javascript
import React from "react";
import {
Link,
NavLink,
useNavigate,
useRoutes,
} from "react-router-dom";
import "./style.css";
// import Home from "./pages/Home";
// import About from "./pages/About";
// import Login from "./pages/Login";
// import NotFound from "./pages/NotFound";
// import HomeRecommend from "./pages/HomeRecommend";
// import HomeRanking from "./pages/HomeRanking";
// import Category from "./pages/Category";
// import Order from "./pages/Order";
// import HomeSangMenu from "./pages/HomeSangMenu";
// import Detail from "./pages/Detail";
// import User from "./pages/User";
import routes from "./router";
export function App(props) {
const navigate = useNavigate();
function navigateTo(path) {
console.log(path);
navigate(path);
}
return (
<div className="app">
<div className="header">
<span>header</span>
<div className="nav">
<NavLink to="/home">首页</NavLink>
<NavLink to="/about">关于</NavLink>
<NavLink to="/login">登陆</NavLink>
<button onClick={(e) => navigateTo("/category")}>分类</button>
<span onClick={(e) => navigateTo("/order ")}>订单</span>
<Link to="/user?name=test&age=18">用户</Link>
</div>
<hr />
</div>
<div className="content">
{/* 映射关系: path => Component */}
{/* <Routes>
<Route path="/" element={<Navigate to="/home" />} />
<Route path="/home" element={<Home />}>
<Route path="/home" element={<Navigate to="/home/recommend" />} />
<Route path="/home/recommend" element={<HomeRecommend />} />
<Route path="/home/ranking" element={<HomeRanking />} />
<Route path="/home/songmenu" element={<HomeSangMenu />} />
</Route>
<Route path="/about" element={<About />} />
<Route path="/login" element={<Login />} />
<Route path="/category" element={<Category />} />
<Route path="/order" element={<Order />} />
<Route path="/detail/:id" element={<Detail />} />
<Route path="/user" element={<User />} />
<Route path="*" element={<NotFound />} />
</Routes> */}
{useRoutes(routes)}
</div>
<div className="footer">Footer</div>
</div>
);
}
export default App;
查看运行效果,与之前保持一致:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AByH8LHr-1690721021332)(https://gitee.com/outmanm78/markdown-image/raw/master/img/202307302029353.png)]
虽然成功抽离了路由配置信息,但是目前的方式,会导致路由统一打包,没有分包处理。我们可以进行改造一下,针对部分配置进行分包处理,实现路由懒加载:
javascript
import React from "react";
import Home from "../pages/Home";
// import About from "../pages/About";
// import Login from "../pages/Login";
import NotFound from "../pages/NotFound";
import HomeRecommend from "../pages/HomeRecommend";
import HomeRanking from "../pages/HomeRanking";
import Category from "../pages/Category";
import Order from "../pages/Order";
import HomeSangMenu from "../pages/HomeSangMenu";
import Detail from "../pages/Detail";
import User from "../pages/User";
import { Navigate } from "react-router-dom";
// 通过React.lazy实现About和Login界面的路由懒加载
const About = React.lazy(() => import("../pages/About"));
const Login = React.lazy(() => import("../pages/Login"));
在src/index.js中,用Suspense
对App进行包裹,实现对分包加载的等待:
javascript
import React, { Suspense } from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { HashRouter } from "react-router-dom";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<HashRouter>
<Suspense fallback={<h3>Loading...</h3>}>
<App />
</Suspense>
</HashRouter>
</React.StrictMode>
);
查看效果,与之前保持一致,懒加载实现成功: