1. Router的基本使用
1.1 安装
- react-router包含一些react-native的内容,web开发并不需要,所以安装 react-router-dom
npm install react-router-dom
1.2 选择路由组件
-
BrowserRouter/HashRouter => App
-
Router中包含了对路径改变的监听,并且会将相应的路径传递给子组件
-
BrowserRouter使用history模式
-
HashRouter使用hash模式
root.render( <React.StrictMode> <HashRouter> <App /> </HashRouter> </React.StrictMode> ); -
1.3 配置映射关系和跳转
-
Routes:包裹所有的Route,在其中匹配一个路由
- Router5.x使用的是Switch组件
-
Route:Route用于路径的匹配
-
path属性:用于设置匹配到的路径
-
element属性:设置匹配到路径后,渲染的组件
- Router5.x使用的是component属性
-
exact:精准匹配,只有精准匹配到完全一致的路径,才会渲染对应的组件
- Router6.x不再支持该属性
-
-
Link:
- 通常路径跳转使用Link组件,最终被渲染成 a 元素
- to属性:用于设置跳转到的路径
- replace:替换当前路径
import React, { PureComponent } from 'react'
import { Link, Route, Routes } from 'react-router-dom'
import About from './pages/About'
import Home from './pages/Home'
export default class App extends PureComponent {
render() {
return (
<div className='app'>
<div className="header">
<span>Header</span>
<div className="nav">
<Link to='/home'>首页</Link>
<Link to='/about'>关于</Link>
</div>
<hr />
</div>
<div className="content">
{/* 映射关系: path => component */}
<Routes>
<Route path='/home' element={<Home/>} />
<Route path='/about' element={<About/>} />
</Routes>
</div>
<div className="footer">
<hr />
Footer
</div>
</div>
)
}
}
2. NavLink使用
-
与
Link的不同- style:传入函数,函数接受一个对象,包含isActive属性
- className:传入函数,函数接受一个对象,包含isActive属性
-
默认的activeClassName:
- 事实上在默认匹配成功时,NavLink就会添加上一个动态的
activeclass
- 事实上在默认匹配成功时,NavLink就会添加上一个动态的
import React, { PureComponent } from 'react'
import { NavLink, Route, Routes } from 'react-router-dom'
import About from './pages/About'
import Home from './pages/Home'
export default class App extends PureComponent {
render() {
return (
<div className='app'>
<div className="header">
<span>Header</span>
<div className="nav">
{/* <NavLink to='/home' style={({isActive}) => ({color: isActive ? 'blue' : ''})}>首页</NavLink>
<NavLink to='/about' style={({isActive}) => ({color: isActive ? 'blue' : ''})}>关于</NavLink> */}
<NavLink to='/home' className={({isActive}) => isActive ? 'link-active' : ''}>首页</NavLink>
<NavLink to='/about' className={({isActive}) => isActive ? 'link-active' : ''}>关于</NavLink>
</div>
<hr />
</div>
<div className="content">
{/* 映射关系: path => component */}
<Routes>
<Route path='/home' element={<Home/>} />
<Route path='/about' element={<About/>} />
</Routes>
</div>
<div className="footer">
<hr />
Footer
</div>
</div>
)
}
}
3. Navigate使用
-
Navigate用于路由的重定向,当这个组件出现时,就会执行跳转到对应的to路径中
-
登录的自动跳转
{!isLogin ? <button onClick={e => this.login()}>登录</button> : <Navigate to='/home' />}
-
根路径的重定向
<Route path='/' element={<Navigate to='/home' />} />
4. NotFound页面配置
-
开发一个Not Found页面
-
配置对应的Route,并且设置path为
*即可<Route path='*' element={<NotFound/>} />
5. 路由嵌套的使用
-
父路由包含子路由
<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> <Route path="/about" element={<About/>} /> <Route path="/login" element={<Login/>} /> <Route path="*" element={<NotFound/>} /> </Routes> -
Outlet占位
import React, { PureComponent } from 'react' import { Link, Outlet } from 'react-router-dom' export default class Home extends PureComponent { render() { return ( <div> <h1>Home Page</h1> <div className="home-nav"> <Link to="/home/recommend">推荐</Link> <Link to="/home/ranking">排行</Link> </div> {/* 占位的组件 */} <Outlet/> </div> ) } }
6. 代码进行跳转
-
如果希望通过
JavaScript代码进行跳转,需要获得 navigate 对象 -
在 Router6.x 之后,代码类的 API 迁移到了hooks中
- 如果用代码跳转,需要通过 useNavigate 的Hook获取到navigte对象进行操作
- 这种 Hook 只能在函数式组件中调用
-
将 App 更改为函数式组件
import React from 'react' import { Link, Navigate, Route, Routes, useNavigate } from 'react-router-dom' import About from './pages/About' import Home from './pages/Home' import HomeRanking from './pages/HomeRanking' import HomeRecommend from './pages/HomeRecommend' import Login from './pages/Login' import Category from './pages/Category' import Order from './pages/Order' import NotFound from './pages/NotFound' export default function App(props) { // 必须放在顶层使用 const navigate = useNavigate() function navigateTo(path) { navigate(path) } return ( <div className='app'> <div className="header"> <span>Header</span> <div className="nav"> <Link to="/home">首页</Link> <Link to="/about">关于</Link> <Link to="/login">登录</Link> <button onClick={e => navigateTo("/category")}>分类</button> <span onClick={e => navigateTo("/order")}>订单</span> </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> <Route path="/about" element={<About/>} /> <Route path="/login" element={<Login/>} /> <Route path="/category" element={<Category/>} /> <Route path="/order" element={<Order/>} /> <Route path="*" element={<NotFound/>} /> </Routes> </div> <div className="footer"> <hr /> Footer </div> </div> ) } -
在类组件如何通过 代码进行跳转呢?
- 封装一个高阶组件,传入 navigate
// with_router.js 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 -
类组件中使用
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 Page</h1> <div className="home-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)
7. 路由传递参数
-
动态路由
- useParams
<Route path='/detail/:id' element={<Detail/>}/>
-
search传递参数
- useSearchParams
<Link to="/user?name=zhangsan&age=20">用户</Link>
-
withRouter 高阶组件升级
// with_router.js import { useLocation, useNavigate, useParams, useSearchParams } from 'react-router-dom' function withRouter(WrapperComponent) { return function(props) { // 1.导航 const navigate = useNavigate() // 2.动态路由参数 const params = useParams() // 3.查询字符的参数 const location = useLocation() const [searchParams] = useSearchParams() const query = Object.fromEntries(searchParams) const router = { navigate, params, location, query } return <WrapperComponent {...props} router={router}/> } } export default withRouter
8. 路由的配置方式
-
在 Router6.x 中,提供了useRoutes API可以完成相关的配置
<div>{useRoutes(routes)}</div>
-
routes 配置
- path:路径
- element:组件
- children:子级路由
import { Navigate } from 'react-router-dom' import Home from '../pages/Home' import HomeRanking from '../pages/HomeRanking' import HomeRecommend from '../pages/HomeRecommend' import HomeSongMenu from '../pages/HomeSongMenu' import About from '../pages/About' import Login from '../pages/Login' import Category from '../pages/Category' import Order from '../pages/Order' import Detail from '../pages/Detail' import User from '../pages/User' import NotFound from '../pages/NotFound' 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/songmenu", element: <HomeSongMenu/> } ] }, { path: "/about", element: <About/> }, { 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
9. 路由的懒加载
-
分析打包后的文件
-
未使用懒加载
main.eb3f0b10.jsmain.js(哈希值) 中存放的是所有的js代码
-
使用懒加载
-
对于懒加载的组件进行单独打包
-
-
-
如何使用懒加载?
- 导入:React.lazy(() => import())
const About = React.lazy(() => import('../pages/About')) const Login = React.lazy(() => import('../pages/Login'))- Suspense fallback
// index.js 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> );