基本使用
1.安装:
npm install react-router-dom
2.设置路由模式:HashRouter/BrowserRouter
import React 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><App /></HashRouter></React.StrictMode>
);
3.路由配置和跳转
- path属性:用于设置匹配到的路径
- element属性:设置匹配到路径后,渲染的组件(Router5.X中使用component属性)
- exact:精确匹配,只有精准匹配到完全一致的路径才渲染对应组件(Router6.X已经不支持)
使用Link组件:最终会被渲染成a元素
import React, { PureComponent } from 'react'
import { Link, Route, Routes } from 'react-router-dom'
import Home from './pages/Home'
import About from './pages/About'
import Profile from './pages/Profile'export class App extends PureComponent {render() {return (<div><div className="header"><Link to="/home">Home</Link><Link to="/about">About</Link><Link to="/profile">Profile</Link></div><div className="main">{/* 配置映射关系:path => Component */}<Routes><Route path="/home" element={<Home />} /><Route path="/about" element={<About />} /><Route path="/profile" element= {<Profile />} /></Routes></div><div className="footer">Footer</div></div>)}
}export default App
NavLink:当前路由选中时,会自动添加一个active的类
4.Navigate导航:可用于路由重定向
<div className="main">{/* 配置映射关系:path => Component */}<Routes>{/* 当路径为"/"时,重定向到"/home" */}<Route path="/" element={<Navigate to="/home" />} /><Route path="/home" element={<Home />} /><Route path="/about" element={<About />} />{/* 当路径匹配不到时,重定向到"/NotFound" */}<Route path="*" element={<NotFound />} /></Routes>
</div>
路由嵌套
需求:在Home组件中再嵌套两个子组件HomeRecommend和HomeRanking
1.路由嵌套配置
<div className="main">{/* 配置映射关系: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/rank" element= {<HomeRanking/>} /></Route><Route path="/about" element={<About />} /><Route path="/profile" element= {<Profile />} /><Route path="/login" element={<Login />} /><Route path="*" element={<NotFound />} /></Routes>
</div>
2.展示二级路由对应组件
<div><h1>Home</h1><div className="home-nav"><Link to="/home/recommend">推荐</Link><Link to="/home/rank">排行</Link></div>{/* 占位的组件 */}<Outlet />
</div>
手动路由跳转
Link渲染出来的是a标签,如果我们想要其它的标签,那就只能自己来操作了
函数式组件跳转
import React from 'react'
import { Link, Navigate, Route, Routes, useNavigate } from 'react-router-dom'
import Order from './pages/Order'
import Category from './pages/Category'export function App (props) {const navigate = useNavigate()function navigateTo(path) {navigate(path)}return (<div><div className="header"><button onClick={e => navigateTo("/category")}>分类</button><span onClick={e => navigateTo("/order")}>订单</span></div><hr /><div className="main"><Routes><Route path="/order" element= {<Order />} /><Route path="category" element= {<Category />} /><Route path="*" element={<NotFound />} /></Routes></div><hr /><div className="footer">Footer</div></div>)
}export default App
类组件跳转
1.封装一个高阶组件,给类组件注入这个hook,然后通过props就能调用并传参
import { useNavigate } from "react-router-dom"
// 封装一个高阶组件
function withRouter(WrappedComponent) {return function(props) {const navigate = useNavigate()const router = {navigate}return <WrappedComponent {...props} router={router}/>}
}export default withRouter
2.在组件中使用
import React, { PureComponent } from 'react'
import { Link, Outlet} from 'react-router-dom'
import withRouter from '../hoc/with_router';export class Home extends PureComponent {navigateTo(path) {console.log(path);const {navigate} = this.props.routernavigate(path)}render() {return (<div><h1>Home</h1><div className="home-nav"><Link to="/home/recommend">推荐</Link><Link to="/home/rank">排行</Link><button onClick={e => this.navigateTo("/home/songmenu")}>歌单</button></div>{/* 占位的组件 */}<Outlet /></div>)}
}export default withRouter(Home)
路由跳转传参
动态路由传参
1.配置路由路径
<Route path="/detail/:id" element= {<Detail />} />
2.点击后跳转到详情并携带id参数
高阶组件-src/hoc/with_router.js
import { useNavigate, useParams, useSearchParams } from "react-router-dom"
// 封装一个高阶组件
function withRouter(WrappedComponent) {return function(props) {// 1.导航参数const navigate = useNavigate()// 2.动态路由参数const params = useParams()// 3.查询字符串的参数const [searchParams] = useSearchParams()const query = Object.fromEntries(searchParams)const router = {navigate,params,query}return <WrappedComponent {...props} router={router}/>}
}export default withRouter
HomeSongMenu.jsx:
import React, { PureComponent } from 'react'
import withRouter from '../hoc/with_router';export class HomeSongMenu extends PureComponent {constructor(props) {super(props)this.state={songMenus:[{id:111,name:"华语流行"},{id:112,name:"古典音乐"},{id:113,name:"民谣歌曲"},{id:114,name:"摇滚音乐"},{id:115,name:"R&B"}]}}NavigateTo(id) {const {navigate} = this.props.router;navigate('/detail/' + id)}render() {const {songMenus} = this.state; return (<div><h1>HomeSongMenu</h1><ul>{songMenus.map((item,index) => {return <li onClick={e => this.NavigateTo(item.id)} key={item.id}>{item.name}</li>})}</ul></div>)}
}export default withRouter(HomeSongMenu)
query传参
import React from 'react'
import { Link, Navigate, Route, Routes, useNavigate } from 'react-router-dom'
import User from './pages/User'export function App (props) {const navigate = useNavigate()function navigateTo(path) {navigate(path)}return (<div><div className="header"><Link to="/user?name=why&age=19">用户</Link></div><hr /><div className="main">{/* 配置映射关系:path => Component */}<Routes><Route path="/user" element= {<User />} /><Route path="*" element={<NotFound />} /></Routes></div><hr /><div className="footer">Footer</div></div>)
}export default App
User.jsx:
import React, { PureComponent } from 'react'
import withRouter from '../hoc/with_router'export class User extends PureComponent {render() {const {router} = this.propsconst {query} = routerreturn (<div>User:{query.name}-{query.age}</div>)}
}export default withRouter(User)
路由配置
将App.js中配置的路由单独抽取到router/index.js文件中
import { Navigate } from "react-router-dom"
import Home from "../pages/Home"
import About from '../pages/About'
import Profile from '../pages/Profile'
import Login from '../pages/Login'
import NotFound from '../pages/NotFound'
import HomeRecommend from '../pages/HomeRecommend'
import HomeRanking from '../pages/HomeRanking'
import HomeSongMenu from '../pages/HomeSongMenu'
import Order from '../pages/Order'
import Category from '../pages/Category'
import Detail from '../pages/Detail'
import User from '../pages/User'const routes = [{path:"/",element:<Navigate to="/home"/>},{path:"/home",element:<Home/>,children:[{path:"/home/recommend",element:<HomeRecommend/>},{path:"/home/rank",element:<HomeRanking/>},{path:"/home/songmenu",element:<HomeSongMenu/>}]},{path:"/about",element:<About/>},{path:"/profile",element:<Profile/>},{path:"/login",element:<Login/>},{path:"/category",element:<Category/>},{path:"/order",element:<Order/>},{path:"/detail/:id",element:<Detail/>},{path:"/user",element:<User/>},{path:"*",element:<NotFound />}
]export default routes
在根组件中使用:App.jsx
import {useRoutes } from 'react-router-dom'
<div className="main">{/* 配置映射关系:path => Component */}{/* useRoutes()是一个函数调用,所有可以在类组件中使用 */}{useRoutes(routes)}
</div>
路由懒加载
可单独打包,匹配到该路径才会下载对应的文件——性能优化
import { Navigate } from "react-router-dom";
import React, { lazy } from 'react';// 使用 React.lazy 进行懒加载
const Home = lazy(() => import('../pages/Home'));
const About = lazy(() => import('../pages/About'));
const Profile = lazy(() => import('../pages/Profile'));
const Login = lazy(() => import('../pages/Login'));
const NotFound = lazy(() => import('../pages/NotFound'));
const HomeRecommend = lazy(() => import('../pages/HomeRecommend'));
const HomeRanking = lazy(() => import('../pages/HomeRanking'));
const Order = lazy(() => import('../pages/Order'));
const Category = lazy(() => import('../pages/Category'));
const HomeSongMenu = lazy(() => import('../pages/HomeSongMenu'));
const Detail = lazy(() => import('../pages/Detail'));
const User = lazy(() => import('../pages/User'));const routes = [{path: "/",element: <Navigate to="/home" />},{path: "/home",element: <Home />,children: [{path: "recommend",element: <HomeRecommend />},{path: "rank",element: <HomeRanking />},{path: "songmenu",element: <HomeSongMenu />}]},{path: "/about",element: <About />},{path: "/profile",element: <Profile />},{path: "/login",element: <Login />},{path: "/category",element: <Category />},{path: "/order",element: <Order />},{path: "/detail/:id",element: <Detail />},{path: "/user",element: <User />},{path: "*",element: <NotFound />}
];export default routes;
导入Suspense并包裹根组件,当匹配的组件还未加载成功时,可显示fallback中的内容
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { HashRouter } from 'react-router-dom';
import { Suspense } from 'react';const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<HashRouter><Suspense fallback={<div>加载中</div>}><App /></Suspense></HashRouter>
);