# 路由
在 React
中可以使用 react-router-dom
来实现前端路由功能。它使用分别暴露暴露出一些组件以供我们使用。
常用的内置路由组件有:
<BrowserRouter>
用 BrowserRouter 标签包裹整个页面,使页面有一个全局的管理路由关系的路由器。并将路由的模式设置为常规路由模式,类似于 Vue 中 history 模式
<HashRouter>
HashRouter 标签和 BrowserRouter 一样,只是路由模式变更为 hash 模式
<Route>
Route 标签是控制路由组件的显示和隐藏,并且可以使用
exact={true}
将路由匹配模式设置为精准匹配,而不是默认的模糊匹配。若该路由下还有子路由,则不能使用精准匹配模式<Redirect>
Redirect 标签是设置一个默认的重定向路由,我们可以使用它设定默认路由。当所有路由匹配失败时,也会重定向到该路由
<Link>
Link 标签是用于更改地址栏的路径,当我们点击该标签时地址栏的路径就会变成该标签的路径
<NavLink>
NavLink 标签能够设定导航的默认样式,利用
activeClassName="指定样式类"
可以将导航标签的样式设置为指定的类的样式<Switch>
Switch 标签的功能是将原本路由的全匹配模式改为匹配完即终止,默认当匹配到多个 Route 标签时会将所有的匹配到的路由组件展示,使用 Switch 包裹则当匹配到第一 Route 时即停止往下匹配
例如我们要实现一个页面的路由切换,那你能利用 <Link>
和 <Route>
组件将路由组件和跳转标签关联起来。
// index.jsx
// 使用history模式路由
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import {BrowserRouter} from 'react-router-dom'
ReactDOM.render(
<BrowserRouter>
<App/>
</BrowserRouter>,
document.getElementById('root'))
// app.jsx
// 需求:点击标签跳转到about页面,并启用replace模式和精准匹配
// 设置默认页面为404
// 设置初次匹配到即停止
import React, { Component } from 'react'
import Home from './components/Home'
import About from './components/About'
import DefaultPage from './components/404'
import {NavLink,Route,Redirect,Switch} from 'react-router-dom'
export default class App extends Component {
render(){
return (
<div>
<ul>
<li>
<NavLink to="/about" activeClassName="demo" replace={true}>AboutPage</NavLink>
<NavLink to="/home" activeClassName="demo">HomePage</NavLink>
</li>
</ul>
<div>
<Switch>
<Route path="/about" exact={true}></Route>
<Route path="/home"></Route>
<Redirect to="/about">
</Switch>
</div>
</div>
)
}
}
# 路由传参
有时候我们想在路由跳转的时候携带一些参数给对应的路由组件,路由组件可以根据传递过来的参数发送网络请求。在 React
当中有总共有三种路由传参的方式,分别是:
- params 传参
- search 传参
- state 传参
# params 传参
params
传参就是利用地址栏里的 params
参数进行参数的传递,例如组件 A 给组件 B 传递两个 params 参数 id
和 name
// A.jsx
import React,{Component} from 'react'
import {Link,Route,Router} from 'react-router-dom'
import B from "./B.jsx"
export default class A extends Component {
state = {
id:"001",
name:"asuhe"
}
render(){
return (
<div>
<div>
<Link to={`/b/${this.state.id}/${this.state.name}`}>click</Link>
</div>
<div>
{/* react-router-dom v6版本以下写法 */}
{/* <Route path="/b/:id/:name" component={B} /> */}
<Routes>
<Route path="/b/:id/:name" element={<B></B>} />
</Routes>
</div>
</div>
)
}
}
而在组件 B 中,我们可以在 props 中接收到多个属性对象,传入的 params 参数我们可以在组件 B 的 props 对象中的 match 里的 params 中获取。
// B.jsx
import React,{Component} from "react"
export default class B extends Component {
render(){
console.log(this.props)
}
}
# react-router-dom v5.x
//路由链接(携带参数):
<Link to='/demo/test/tom/18'}>详情</Link>
//或 <Link to={{ pathname:'/demo/test/tom/18' }}>详情</Link>
//注册路由(声明接收):
<Route path="/demo/test/:name/:age" component={Test}/>
//接收参数:
this.props.match.params
# react-router-dom v6.x
//路由链接(携带参数):
<Link to={{ pathname:`/b/child1/${id}/${title}` }}>Child1</Link>
//或 <Link to={`/b/child1/${id}/${title}`}>Child1</Link>
//注册路由(声明接收):
<Route path="/b/child1/:id/:title" component={Test}/>
//接收参数:
import { useParams } from "react-router-dom";
const params = useParams();
//params参数 => {id: "01", title: "消息1"}
# search 传参
React
中的 search
传参实际上就是我们传统请求参数中的 query
传参。只是写法稍微有些差异。
// A.jsx
render(){
return(
<div>
<div>
<Link to={`/b?id=${this.state.id}&$name={this.state.name}`}>点击跳转至组件B</Link>
</div>
<div>
<Router>
<Route path="/b" component={B}></Route>
</Router>
</div>
</div>
)
}
传入的 search 参数我们可以在组件 B 的 props 对象中的 location 里的 search 中获取。
# react-router-dom v5.x
//路由链接(携带参数):
<Link to='/demo/test?name=tom&age=18'}>详情</Link>
//注册路由(无需声明,正常注册即可):
<Route path="/demo/test" component={Test}/>
//接收参数:
this.props.location.search
//备注:获取到的search是urlencoded编码字符串(例如: ?id=10&name=zhangsan),需要借助query-string解析参数成对象
# react-router-dom v6.x
//路由链接(携带参数):
<Link className="nav" to={`/b/child2?age=20&name=zhangsan`}>Child2</Link>
//注册路由(无需声明,正常注册即可):
<Route path="/b/child2" component={Test}/>
//接收参数方法1:
import { useLocation } from "react-router-dom";
import qs from "query-string";
const { search } = useLocation();
//search参数 => {age: "20", name: "zhangsan"}
//接收参数方法2:
import { useSearchParams } from "react-router-dom";
const [searchParams, setSearchParams] = useSearchParams();
// console.log( searchParams.get("id")); // 12
//备注:获取到的search是urlencoded编码字符串(例如: ?age=20&name=zhangsan),需要借助query-string解析参数成对象
# state 传参
state
传参就是把 <Link>
里面的 to
属性换成一个对象,再将路径和参数信息填入该对象。
// A.jsx
render(){
<div>
<div>
<Link to={{pathname:"/b",state:{id:this.state.id,name:this.state.name}}}>点击跳转至组件B</Link>
</div>
<div>
<Router>
<Route path="/b" component={B}></Route>
</Router>
</div>
</div>
)
}
传入的 state 参数我们可以在组件 B 的 props 对象中的 location 里的 state 中获取。
# react-router-dom v5.x
//路由链接(携带参数):
<Link to={{pathname:'/demo/test',state:{name:'tom',age:18}}}>详情</Link>
//注册路由(无需声明,正常注册即可):
<Route path="/demo/test" component={Test}/>
//接收参数:
this.props.location.state
//备注:刷新也可以保留住参数
# react-router-dom v6.x
//通过Link的state属性传递参数
<Link
className="nav"
to={`/b/child2`}
state={{ id: 999, name: "i love merlin" }}
>
Child2
</Link>
//注册路由(无需声明,正常注册即可):
<Route path="/b/child2" component={Test}/>
//接收参数:
import { useLocation } from "react-router-dom";
const { state } = useLocation();
//state参数 => {id: 999, name: "我是asuhe"}
//备注:刷新也可以保留住参数
# 编程式路由
编程式路由可以允许我们用 javascript
动态生成路由链接
# react-router-dom v5.x
// A.jsx
class A extends Component {
pushRoute = ()=>{
this.props.history.push("/b")
}
render(){
return (
<div>
<button onClick={this.pushRoute}></button>
<Route path="/b" component={B}/>
</div>
)
}
}
# react-router-dom v6.x
function A {
const navigate = useNavigate()
navigate('b', {
state: {
id: item.id,
content: item.content,
title: item.title
}
})
return (
<div>
<button onClick={() => navigate(-1)}>back</button>
<button onClick={() => navigate(1)}>go</button>
</div>
)
}
# withRouter
当我想要在非路由组件中使用路由组件中的 push
、 replace
等编程式路由的函数时,就可以使用 withRouter
来获取这些函数。 withRouter
作为一个高阶组件,其作用是将一个组件包裹进 Route
里面,然后 react-router
的三个对象 history,、location、match
就会被放进这个组件的 props 属性中。
import React, { Component } from 'react'
import {withRouter} from 'react-router-dom'
class C extends Component {
back = ()=>{
this.props.history.goBack()
}
forward = ()=>{
this.props.history.goForward()
}
render() {
return (
<div >
<button onClick={this.back}>回退</button>
<button onClick={this.forward}>前进</button>
</div>
)
}
}
export default withRouter(C)