react路由分三种,这里主要介绍 react-rotuer-dom
-
BrowserRouter:最大的容器,全局只能有一个,route所有的配置都要放在里面才会有效果 Browser(有浏览器的意思) 所以一般直接包裹app.js的根元素。
- forceRefresh:控制react-router跳转的时候刷新页面或不刷新页面,值为boolean
使用:<BrowserRouter forceRefresh={true}></BrowserRouter>
- forceRefresh:控制react-router跳转的时候刷新页面或不刷新页面,值为boolean
-
HashRouter:与BrowserRouter作用相同,不同是以hash的方式进行跳转。
-
Link :
<Link to="/name">
进行跳转 -
Route :
<Route path="/name" component={Name} />
进行匹配 -
NavLink:Link的升级版,自带”active“ class名
- 属性:activeClassName: 修改高亮的class名
-
Switch:提高效率,优化匹配机制,检测到相同的path之后,不会继续向下传递
为什么使用Switch?
重复的path会让两个组件同时显示,所以由两个或两个以上的Route,就需要使用Switch包裹 -
Redirect:一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由
<Redirect to="/home">
-
withRouter:让一般组件实现路由跳转
-
Prompt: React 阻止路由离开(路由拦截)
<Prompt when={true} message={location => '信息还没保存,确定离开吗?'}
/>
```
一般组件与路由组件
- 写法不同:
一般组件:</Demo/>
路由组件:<Route path="/demo" component={Demo}></Route>
- 接收到props不同
一般组件:写组件标签时传递的什么,就能收到什么
路由组件:接收到三个固定的属性- history:
- go
- goBack
- goForward
- push:fn(path,state)
- replace:fn(path,state)
- localtion:
- pathname
- search
- state:undefined
- match:
- params:{}
- path:"/about"
- url:"/about"
- history:
精准匹配&模糊匹配
- 模糊匹配(默认):【输入的路径】必须包含要【匹配的路径】,且顺序要一致
<NavLink to="/home/a"></NavLink>
添加属性replace={true}
,开启replace模式
<Route path="/home" component={Home}></Route>
- 精准匹配:Route中添加exact属性
【注意】严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由
值为Boolean ,默认为true
<Route exact path="/home" component={Home}></Route>
路由传参的三种方式
- 向路由组件传递params参数
路由链接(传递参数)
<Link to="home/news/detail/1"></Link>
注册路由(声明接收)
<Route path="home/news/detail/:type" component={Detail}></Route>
子组件通过props.match.params
接收参数
- 传递search参数
路由链接(会将属性和值一块传递)
<Link to="home/news/detail?id=1&title='标题1'"></Link>
注册路由(正常写即可)
<Route path="home/news/detail" component={Detail}></Route>
子组件通过props.localtion.serach
可以拿到“?id=1&title=‘标题1’” urlencoded编码字符串
通过简单处理就可以使用
react有自带的方法
import qs from 'querystring
有stringify 和jsonparse 两个方法(和JSON的方法一样)
- state参数(隐式传参,与组件状态的state无关,不同于vue的隐式传参,刷新可以保留参数)
优点:传递的参数在地址栏中是不显示的
路由链接(对象的方式传递,两个属性pathname和state)
<Link to={{pathname:'home/news/detail',state:{id:1,title:'标题1'}}}></Link>
注册路由(正常写即可)
<Route path="home/news/detail" component={Detail}></Route>
子组件通过props.localtion.state
接收参数
编码方式(传参形式)?????
urlencoded JSON query params
一般组件实现路由跳转(withRouter)
withRouter可以加工一般组件,让一般组件具备组件所特有的API
withRouter返回值是一个新组建(包含路由组件的API)
import {withRouter} from 'react-router-dom'
导出组件时导出的时withRouter(Header)函数的返回值
BrowserRouter与HashRouter的区别?
1、底层原理不一样:
- BrowserRouter使用的是H5的history的API,不兼容IE9及以下的版本。
- HashRouter使用的是URL的哈希值
2、path的表现形式不一样
- BrowserRouter的路径没有#,例如:localhost:3000/demo/test
- HashRouter的路径包含#,例如:localhost:3000/#/demo/test
3、刷新后对路由state参数的影响
- BrowserRouter没有任何影响,因为state保存在history对象中
- HashRouter刷新后会导致路由state参数的丢失
4、【备注】:HashRouter可以用于解决一些路径错误相关的问题
这里来一个小例子
场景:常见的列表中获取某一条数据的详情。
三个组件:
- index.jsx :根组件
- List.jsx:列表组件
- Detail.jsx:详情组件
//index
import React, { Component } from 'react';
import { NavLink, Route, Switch, Redirect } from 'react-router-dom'
import List from './List';
import Detail from './Detail';
class View extends Component {
state = {
list:[]
}
render() {
return (
<React.Fragment>
<NavLink to="/list"/>
<Switch>
<Route path="/list" component={List}></Route>
<Route path="/Detail/:type" component={Detail}></Route>
<Redirect to="/list" />
</Switch>
</React.Fragment>
);
}
}
export default View;
//List组件
import React, { Component } from 'react'
import axios from '../../unit'
export class List extends Component {
state = {
list:[]
}
componentDidMount() {
// 请求数据
axios('get', '/home/mediareports?', { page_number: 1, page_size: 20 }).then(res => {
this.setState({ list: res.data.data })
})
}
// 动态传参
onTarget(id) {
this.props.history.push(`/detail/${id}`)
}
// 渲染页面
rList() {
return this.state.list.map(item => (
<li key={item.id} onClick={()=>{this.onTarget(item.id)}}>
<p>{ item.main_title }</p>
</li>
))
}
render() {
return (
<ul>
{this.rList()}
</ul>
)
}
}
export default List
//Detail组件
import React, { Component } from 'react'
import axios from '../../unit'
export class Detail extends Component {
state = {
obj:{}
}
componentDidMount() {
// 获取数据
axios('get', '/home/mediareports?', { page_number: 1, page_size: 20 }).then(res => {
const data = res.data.data;
// 拿到params参数
const id = this.props.match.params.type;
// 这一块没有获取单个数据接口,所以需要筛选一下
const obj = data.filter(item => item.id === id)[0]
this.setState({obj})
})
}
render() {
let { obj } = this.state
console.log(obj)
return (
<ul>
<li>标题:{ obj.main_title }</li>
<li>来源:{ obj.source }</li>
<li>时间:{ obj.sourceDate }</li>
</ul>
)
}
}
export default Detail
lazy的使用
- 引入:
import React,{ lazy, Suspense } from 'react';
- 使用:
const About = lazy(() => import('地址'))
//必须用Suspense 包裹,默认有一个loading回调
<Suspense fallback={<div>loading...</div>}>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Redirect to="/" />
</Suspense>