路由器组件(<BrowserRouter>、<HashRouter>)
路由匹配组件(<Route>、<Switch>)
导航组件(<Link>、<NavLink>)。
路由组件 BrowserRouter 和 HashRouter
BrowserRouter(history模式) 和 HashRouter(hash模式)作为路由配置的最外层容器,是两种不同的模式,可根据需要选择。
hash模式:
class App extends React.Component{
render(){
return (//映射路由
<HashRouter>
<Route exact path="/public" component={Public}/>
<Route exact path="/login" component={Login}/>
<Route exact path="/home" component={Home}/>
<Redirect exact from='/' to="/public" />
</HashRouter>
);
}
}
项目运行结果:
props:
{
"history": {
"length": 5,
"action": "REPLACE",
"location": "{hash: \"\", pathname: \"/public\", search: \"\", state: …}",
"createHref": "createHref",
"push": "push",
"replace": "replace",
"go": "go",
"goBack": "goBack",
"goForward": "goForward",
"block": "block",
"listen": "listen"
},
"location": {
"pathname": "/public",
"search": "",
"hash": ""
},
"match": {
"path": "/public",
"url": "/public",
"isExact": true,
"params": "{}"
}
}
history模式:
class App extends React.Component{
render(){
return (//映射路由
<BrowserRouter>
<Route exact path="/public" component={Public}/>
<Route exact path="/login" component={Login}/>
<Route exact path="/home" component={Home}/>
<Redirect exact from='/' to="/public" />
</BrowserRouter>
);
}
}
运行结果:
props:
{
"history": {
"length": 5,
"action": "REPLACE",
"location": "{hash: \"\", key: \"iu0aod\", pathname: \"/public\", sear…}",
"createHref": "createHref",
"push": "push",
"replace": "replace",
"go": "go",
"goBack": "goBack",
"goForward": "goForward",
"block": "block",
"listen": "listen"
},
"location": {
"pathname": "/public",
"search": "",
"hash": "",
"key": "iu0aod"
},
"match": {
"path": "/public",
"url": "/public",
"isExact": true,
"params": "{}"
}
}
以上是使用history与hash模式的结果整理,从控制台输出props中发现使用history比hash模式在location对象中多了一个key属性,以及url中hash模式多了#。暂且还未发现什么不同,如后续深究会在更新~
路由匹配组件:Route,Switch
Route:用来控制路径对应显示的组件,有以下几个参数:
path:指定路由跳转路径
exact:精确匹配路由
componnet:路由对应的组件
import Home from "./pages/Home/Home";
......
<Route exact path="/home" component={Home}/>
render: 通过写render函数返回具体的dom:
<Route path='/home' exact render={() => (<div>home</div>)}></Route>
render 也可以直接返回 Home组件,像下面:
<Route path='/home' exact render={() => <Home/>}></Route>
也可以通过 render 方法传递 props 属性,并且可以传递自定义属性:
<Route path='/home' exact render={(props) => {
return <Home {...props} name={'Ali'}/>
}}/>
然后,就可在 Home组件中获取 props 和 name 属性:
import React from 'react'
class Home extends React.Component{
state={
name:''
}
componentDidMount() {
var name = this.props.name
this.setState({name})
}
render() {
return(
<h1>{this.state.name}</h1>
)
}
}
export default Home;
render 方法也可用来进行权限认证:
<Route path='/home' exact render={(props) => {
// isLogin 从 redux 中拿到, 判断用户是否登录
return isLogin ? <User {...props} name={'Ali'} /> : <div>请先登录</div>
}}/>
location: 将 与当前历史记录位置以外的位置相匹配,则此功能在路由过渡动效中非常有用
sensitive:是否区分路由大小写
strict: 是否配置路由后面的 '/'
Switch
渲染与该地址匹配的第一个子节点 <Route>
或者 <Redirect>,
类似于选项卡,只是匹配到第一个路由后,就不再继续匹配:
<Switch>
<Route path="/public" component={Public}/>
<Route path="/login" component={Login}/>
<Route path="/home" component={Home}/>
<Redirect from='/' to="/public" />
</Switch>
//类似于:
//switch(Route.path){
// case '/home':
// return Home
// case '/login':
// return Login
// default:
// return Pulic
//}
如果路由 Route 外部包裹 Switch 时,路由匹配到对应的组件后,就不会继续渲染其他组件了。但是如果外部不包裹 Switch 时,所有路由组件会先渲染一遍,然后选择到匹配的路由进行显示。
导航组件:Link,NavLink
Link 和 NavLink 都可以用来指定路由跳转,NavLink 的可选参数更多。
Link
两种配置方式:
通过字符串执行跳转路由
<Link to="/login" >登录</Link>
通过对象指定跳转路由
- pathname: 表示要链接到的路径的字符串。
- search: 表示查询参数的字符串形式。
- hash: 放入网址的 hash,例如 #a-hash。
- state: 状态持续到 location。通常用于隐式传参(埋点),可以用来统计页面来源
<Link to={{
pathname: '/login',
search: '?name=aaa',
hash: '#someHash',
state: { fromWechat: true }
}}>
登录
</Link>
NavLink
可以看做 一个特殊版本的 Link,当它与当前 URL 匹配时,为其渲染元素添加样式属性。
<NavLink
to="/login"
activeStyle={{
fontWeight: 'bold',
color: 'red'
}}
>
<span>登录</span>
</NavLink>
- exact: 如果为 true,则仅在位置完全匹配时才应用 active 的类/样式。
- strict: 当为 true,要考虑位置是否匹配当前的URL时,pathname 尾部的斜线要考虑在内。
- location 接收一个location对象,当url满足这个对象的条件才会跳转
- isActive: 接收一个回调函数,只有当 active 状态变化时才能触发,如果返回false则跳转失败
const oddEvent = (match, location) => {
if (!match) {
return false
}
const eventID = parseInt(match.params.eventID)
return !isNaN(eventID) && eventID % 2 === 1
}
<NavLink
to="/login"
isActive={oddEvent}
>login</NavLink>
Redirect:即用户访问一个路由,会自动跳转到另一个路由。
<Redirect from='/' to="/public" />
上面,当访问路由 '/'时会直接重定向到 '/public'
<Redirect>
常用在用户是否登录:
class Center extends PureComponent {
render() {
const { loginStatus } = this.props;
if (loginStatus) {
return (
<div>个人中心</div>
)
} else {
return <Redirect to='/login' />
}
}
}
也可使用对象形式:
<Redirect
to={{
pathname: "/login",
search: "?name=Ali",
state: { referrer: currentLocation }
}}
/>
withRouter
withRouter 可以将一个非路由组件包裹为路由组件,使这个非路由组件也能访问到当前路由的match, location, history对象。
import { withRouter } from 'react-router-dom';
class Detail extends Component {
render() {
··· ···
}
}
const mapStateToProps = (state) => {
return {
··· ···
}
}
const mapDispatchToProps = (dispatch) => {
return {
··· ···
}
}
export default connect(mapStateToProps, mapDispatchToProps)(withRouter(Detail));
注意:只有通过 Route 组件渲染的组件,才能在 this.props 上找到history对象。
编程式导航 - history 对象
例如,点击img进入登录页:
class Home extends PureComponent {
goHome = () => {
console.log(this.props);
this.props.history.push({
pathname: '/login',
state: {
identityId: 1
}
})
}
render() {
return (
<img className='banner-img' alt='' src="img.png" onClick={this.goHome} />
)
}
}
所以,如果想在路由组件的子组件中使用 history ,需要使用 withRouter 包裹:
import React, { PureComponent } from 'react';
import { withRouter } from 'react-router-dom';
class 子组件 extends PureComponent {
goHome = () => {
this.props.history.push('/home')
}
render() {
console.log(this.props)
return (
<div onClick={this.goHome}>子组件</div>
)
}
}
export default withRouter(子组件);