七、React路由
1.路由v5
1.基本步骤
1.安装react-router-dom模块
yarn add react-router-dom@5.3.02.导入所需模块
App.js
import {
BrowserRouter as Router, // history模式
或
HashRouter as Router, // hash模式
Route, // 用于定义路由
Link // 用于跳转路由(声明式导航)
} from "react-router-dom";3.定义路由
导航区使用 <Link>,展示区使用 <Route>。
App.js
function Dy() { return <div>电影</div> }
function Yy() { return <div>影院</div> }
function Th() { return <div>特惠</div> }
function My() { return <div>我的</div> }
function App() {
return (<fieldset>
<legend>App</legend>
<Router>
<ul>
<li><Link to="/dy">电影</Link></li>
<li><Link to="/yy">影院</Link></li>
<li><Link to="/th">特惠</Link></li>
<li><Link to="/my">我的</Link></li>
</ul>
<hr />
<Route path="/" component={Dy} />
<Route path="/dy" component={Dy} />
<Route path="/yy" component={Yy} />
<Route path="/th" component={Th} />
<Route path="/my"> <My /> </Route>
</Router>
</fieldset>
);
}
export default App;2.路线匹配Switch
作用:Switch 可以提高路由匹配效率,如果匹配成功,则不再继续匹配后面的路由,即单一匹配。
步骤:
1.导入Switch
import { Switch } from "react-router-dom";2.用<Switch></Switch>包裹所有<Route>
<Switch>
<Route path="/" exact component={Dy} />
<Route path="/dy" component={Dy} />
<Route path="/yy" component={Yy} />
<Route path="/th" component={Th} />
<Route path="/my"> <My /> </Route>
</Switch>3.精确匹配exact
默认使用模糊匹配(输入的路径必须包含要匹配的路径,且顺序一致)
开启严格匹配:给<Route/>标签添加exact属性
<Route exact path="/about" component={About}/>严格匹配需要再开,开启可能会导致无法继续匹配二级路由
4.高亮导航NavLink
作用:NavLink 可以实现路由链接的高亮,默认添加一个 active 类名。通过 activeClassName 指定样式名,
步骤:
1.导入
import { NavLink } from "react-router-dom";2.使用
把<Link>换成<NavLink>
<ul>
<li><NavLink to="/dy">电影</NavLink></li>
<li><NavLink to="/yy">影院</NavLink></li>
<li><NavLink to="/th">特惠</NavLink></li>
<li><NavLink to="/my">我的</NavLink></li>
</ul>5.重定向Redirect
作用:当所有路由都无法匹配时,跳转到 Redirect 指定的路由,一般写在所有路由注册的最下方
步骤:
1.导入
import { Redirect } from "react-router-dom";2.使用
<Switch>
<Route path="/about" component="{About}" />
<Route path="/home" component="{Home}" />
<Route path="/404" component={NotFound} />
<Redirect to="/404" />
</Switch>6.路由传参
参数种类:query、params
传参方式:
1.params传参:定义路由时【需要管】刷新【不丢失】
- 定义路由时在路径后加需要的参数名
<Route path="/dyDetail/:id" component={Detail} />- 跳转和获取参数
// 跳转:
this.props.history.push({
pathname:'/路径/6'
})
// 获取:
/this.props.match.params.参数名2.state传参 :定义路由时【不用管】刷新【BrowserRouter不丢失、HashRouter丢失】
// 跳转:
this.props.history.push({
pathname:'/路径',
state:{参数名:值,...}
})
// 获取:
this.props.location.state.参数名2.query传参:定义路由时【不用管】刷新【丢失】
注:此query非比query地址栏是没有? 只是它叫query
// 跳转:
this.props.history.push({
pathname:'/路径',
query:{参数名:值,...}
})
// 获取:
this.props.location.query.参数名其他
this.props.history.go(-1/2数字)7.嵌套路由
- 注册子路由需写上父路由的
path - 路由的匹配是按照注册路由的顺序进行的
父组件
<MyNavLink to="/about">About</MyNavLink>
<MyNavLink to="/home">Home</MyNavLink>
<Switch>
<Route path="/about" component="{About}" />
<Route path="/home" component="{Home}" />
<Redirect to="/about" />
</Switch>子组件
<ul className="nav nav-tabs">
<li>
<MyNavLink to="/home/news">News</MyNavLink>
</li>
<li>
<MyNavLink to="/home/message">Message</MyNavLink>
</li>
</ul>
<Switch>
<Route path="/home/news" component="{News}" />
<Route path="/home/message" component="{Message}" />
<Redirect to="/home/news" />
</Switch>8.withRouter
作用:加工一般组件,让其拥有路由组件的 API ,如 this.props.history.push 等。
语法:
1.从react-router-dom导入withRouter
2.最后导出组件时,使用调用withRouter()方法组件为实参
import React, {Component} from 'react'
import {withRouter} from 'react-router-dom'
class Header extends Component {
...
}
export default withRouter(Header)9.登录鉴权
src/router/private.jsx
import { Route, Redirect } from "react-router-dom"
function PrivateRoute(props) {
// 获取用户信息
let token = localStorage.getItem('token')
// 判断
if (token) {
return <Route {...props} />
}
return <Redirect to="/login" />
}
export default PrivateRoutesrc/router/index.js
import {
BrowserRouter as Router,
Switch,
Route,
Redirect,
} from "react-router-dom";
import PrivateRoute from "./privateRoute";
import Login from "../pages/login";
import Welcome from "../pages/welcome";
import Users from "../pages/users";
import Orders from "../pages/orders";
import Layout from "../layout";
import Err404 from "../components/err/err404";
import Err500 from "../components/err/err500";
function ReactConfig() {
return (
<Router>
<Switch>
<Route path="/" exact component={Login} />
<Route path="/login" component={Login} />
{/* <Route path="/admin" exact component={Layout}/> */}
<Route path="/admin">
<Layout>
<Switch>
{/*
细节1:path一样 && exact 就好比是别名(注:v6有更好的解决方案)
<Route path="/admin/welcome" component={Welcome}/>
细节2:父有404 子得单独写404 (注:v6有更好的解决方案)
*/}
<PrivateRoute path="/admin" exact component={Welcome} />
<PrivateRoute path="/admin/users" component={Users} />
<PrivateRoute path="/admin/orders" component={Orders} />
<Redirect to="/404" />
</Switch>
</Layout>
</Route>
<Route path="/404" component={Err404} />
<Route path="/500" component={Err500} />
<Redirect to="/404" />
</Switch>
</Router>
);
}
export default ReactConfig;10.路由组件懒加载
1.从react中导入lazy,Suspense
import { lazy, Suspense } from "react";2.导入路由组件时用lazy()包裹
const Login = lazy(() => import("../pages/login"));3.用<Suspense fallback={<div>Loading...</div>}> </Suspense>包裹定义的路由组件
- fallbac里的内容是当数据没加载完毕时显示的loading组件
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Switch>
<Route path="/" exact component={Login} />
<Redirect to="/404" />
</Switch>
</Suspense>
</Router>2.路由v6
1.升级说明
- 内置组件的变化:移除
<Switch/>,新增<Routes/>并且不用再使用exact…… - 语法变化:
component={About}变成element={<About/>}…… - 去掉
<Redirect> - 新钩子
useRoutes代替react-router-config。 - 大小减少:从
20kb到8kb - 新增 hook:
useParams、useNavigate、useMatch……
安装路由
yarn add react-router-dom2.基本语法
import {
BrowserRouter as Router, // history模式
或
HashRouter as Router, // hash模式
Routes, // 声明一组路由(注:router@6 将所有`<Switch>`元素升级为`<Routes>`)
Route, // 用于定义路由
Link // 用于跳转路由(声明式导航)
} from "react-router-dom";
<Router>
<ul>
<li><Link to="/dy">电影</Link></li>
<li><Link to="/yy">影院</Link></li>
<li><Link to="/th">特惠</Link></li>
<li><Link to="/my">我的</Link></li>
</ul>
<hr />
<Routes>
<Route path="/" element={<Dy />} />
<Route path="/dy" element={<Dy />} />
<Route path="/yy" element={<Yy />} />
<Route path="/th" element={<Th />} />
<Route path="/my" element={<My />} />
</Routes>
</Router>3.重定向Navigate
v6移除了Redirect
改成如下方式重定向
<Routes>
<Route path="/" element={<Dy />} />
<Route path="/dy" element={<Dy />} />
<Route path="/yy" element={<Yy />} />
<Route path="/th" element={<Th />} />
<Route path="/my" element={<My />} />
<Route path='*' element={<Navigate to='/' />} />
</Routes>4.路由传参
params传参:定义路由时【需要管】刷新【不丢失】
跳转:this.props.history.push({pathname:'/路径/6'}) 获取:this.props.match.params.参数名state传参 :定义路由时【不用管】刷新【BrowserRouter不丢失、HashRouter丢失】
跳转:this.props.history.push({pathname:'/路径', state:{参数名:值,...}}) 获取:this.props.location.state.参数名query传参:定义路由时【不用管】刷新【丢失】
跳转:this.props.history.push({pathname:'/路径', query:{参数名:值,...}}) 获取:this.props.location.query.参数名其他
this.props.history.go(-1/2数字)
| 种类 | hooks名 | 作用 | 语法 |
|---|---|---|---|
| params传参 | useParams | 获取params参数 | const {参数名, ..., } = useParams() |
| state传参 | useLocation | 获取state参数 | const location = useLocation() |
| search传参 | useSearchParams | 获取带?问号的参数 | const [search,setSearch] = useSearchParams() search.get(参数名) setSearch(参数名=值&..&参数名=值) |
| 声明式导航 | <Link> 组件 | <Link to="路径/1"> <Link to="路径?id=1"> | |
| 编程式导航 | useNavigate | const navigate = useNavigate() navigate('路径') navigate( "路径", { state:{} } ) navigate( "路径?id=6" ) navigate( 1或-1 ) |
5.嵌套路由
给<Route>标签添加index属性,标识默认匹配
function ReactRouter() {
return (
<>
<Router>
<Routes>
<Route path="/" element={<Login />} />
<Route path="/login" element={<Login />} />
<Route path="/admin" element={<Layout />}>
<Route index element={<Admin />} />
<Route path="users" element={<Users />} />
<Route path="orders" element={<Orders />} />
</Route>
<Route path="/404" element={<Err404 />}></Route>
<Route path="/500" element={<Err500 />}></Route>
<Route path="*" element={<Navigate to="/" />} />
</Routes>
</Router>
</>
);
}6.useRoutes
集中式路由
src/index.js
import { createRoot } from "react-dom/client";
import App from "./App";
// 导入BrowserRouter
import { BrowserRouter as Router } from "react-router-dom";
const root = createRoot(document.querySelector("#root") as HTMLElement);
// Router包裹根组件
root.render(
<Router>
<App />
</Router>
);routes/index.js
和vue路由类似,嵌套用children
import Dy from '../pages/Dy'
import My from '../pages/My'
import Jb from '../pages/children/Jb'
import Jq from '../pages/children/Jq'
const routes = [
{
path: '/dy',
element: <Dy />,
children:[
{
path:'/dy/jb',
element:<Jb/>
},
{
path:'/dy/jq',
element:<Jq/>
},
]
},
{
path: '/My',
element: <My />,
},
]
export default routesApp.js
- 引入routes
- 创建element
- 在路由需要显示的地方放
{element}
import { NavLink, useRoutes} from "react-router-dom";
import routes from "./router";
const App = () => {
const element = useRoutes(routes);
return (
<fieldset>
<legend>App</legend>
<ul>
<li>
<NavLink to="dy">
电影
<ul>
<li><NavLink to="dy/jb">劲爆电影</NavLink></li>
<li><NavLink to="dy/jq">激情电影</NavLink></li>
</ul>
</NavLink>
</li>
<li>
<NavLink to="My">我的</NavLink>
</li>
</ul>
{element}
</fieldset>
);
};
export default App;src/pages/Dy.jsx
有嵌套路由时,在需要显示的地方放<Outlet/>
import { Outlet } from "react-router-dom";
const Dy = () => {
return (
<fieldset>
<legend>电影区</legend>
<Outlet />
</fieldset>
);
};
export default Dy;