react-router-dom
简介
- react的一个插件库
- 专门用来
基本使用
import React, { Component } from 'react'
import { Link, NavLink, Route, Switch,Redirect } from 'react-router-dom'
import './App.css'
import Home from './pages/Home'
import About from './pages/About'
import Test from './pages/Test'
//创建并暴露App组件,在使用App组件时,需要在<App>的最外侧包裹了一个<BrowserRouter>或<HashRouter>
export default class App extends Component {
render() {
return (
<div>
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
{/*
路由链接可以使用Link或者NavLink,NavLink可以通过activeClassName指定链接
激活(点击)时添加的类名,默认指定的类名是active可以对NavLink进行二次封装
*/}
<Link className="list-group-item" to='/about'>About</Link>
<Link replace={true} className="list-group-item" to='/home'>Home</Link>
{/*
上面 replace={true} 表示 开启的replace模式,还有一种push模式(默认),replace
模式可以实现无痕访问,先访问 /about 然后访问 /home,因为/home开启了replace模式,
访问 /home 时会将 前面的访问记录替换掉,而不是追加一个访问记录
*/}
<NavLink className="list-group-item" to='/about' activeClassName='active'>About</NavLink>
<NavLink className="list-group-item" to='/home' activeClassName='active'>Home</NavLink >
</div>
<div className="col-xs-6">
<Switch>
{/*
Switch标签中的路由匹配上一个就不继续匹配了'./home' 匹配上 组件Home
就不继续匹配 Test组件了*/}
<Route exact={true} path='/about' component={About}></Route>
{/*
exact={true}表示严格匹配,默认开启的默认匹配,上面的一行代
码给'/about'开启了严格匹配,那么它的多级路由都无法正确匹配
了Link标签中to属性的路径和Route标签中path属性的路径一模一
样时才能展示对应的组件to(Link)~/home/a/b/,path(Route)~/home,
可以展示对应的组件 to(Link)~/a/home/b/,path(Route)~/home,
不能展示对应的组件 to(Link)~/home,path(Route)~/home/a/b,
不能展示对应的组件
*/}
<Route path='/home' component={Home}></Route>
<Route path='/home' component={Test}></Route>
<Redirect to='/home'></Redirect>
{/*
Redirect一般写在路由的最下面,当所有的路由都匹配不上的
时候就会按照Recirect来跳转
*/}
</Switch>
</div>
</div>
</div>
)
}
}
嵌套路由
//这里是home组件
import React, { Component } from 'react'
import MyNavLink from '../../components/MyNavLink'
import { Route, Switch, Redirect } from 'react-router-dom'
import News1 from './News1'
import Message1 from './Message1'
export default class Home extends Component {
return (
<div>
<h3>我是Home的内容</h3>
<div>
<ul className="nav nav-tabs">
<li>
<MyNavLink to='/home/news'>News1</MyNavLink>
{/*
to属性的值必须带上一级路由,而且一级路由中不能开启严格匹配
*/}
</li>
<li>
<MyNavLink to='/home/messsage'>Messages1</MyNavLink>
</li>
</ul>
<Switch>
<Route path='/home/new' component={News1}></Route>
{/*
path属性的值必须带上一级路由
*/}
<Route path='/home/new' component={Message1}></Route>
<Redirect to="/home/new" />
</Switch>
</div>
</div>
)
}
}
路由传参
传递params参数
总结
-
路由链接(携带参数):<Link to='/demo/test/tom/18'}>详情
-
注册路由(声明接收):
-
接收参数:this.props.match.params
//home组件中
import React, { Component } from 'react'
import { Link, Route } from 'react-router-dom'
import Detail from './Detail'
export default class Message extends Component {
render() {
state = {
messageArr: [
{ id: '01', title: '消息1' },
{ id: '02', title: '消息2' },
{ id: '03', title: '消息3' },
]
}
render() {
const { messageArr } = this.state
return (
<div>
<ul>
{
messageArr.map((item) => {
return (
<li key={item.id}>
<Link to={`/home/detail/${item.id}/${item.title}`}>{item.title}</Link>
{/*
需要在路由链接中携带params参数,注意需要在注册路由时声明
*/}
</li>
)
})
}
</ul>
<hr />
<Route path='/home/detail/:id/:title' component={Detail}></Route>
{/*在注册路由中声明*/}
</div>
)
}
}
//detail组件中
import React, { Component } from 'react'
const DetailData = [
{ id: '01', content: '你好,中国' },
{ id: '02', content: '你好,尚硅谷' },
{ id: '03', content: '你好,未来的自己' }
]
export default class Detail extends Component {
render() {
const { id, title } = this.props.match.params
{
/*
接收params参数
在路由组件中 通过this.props.match.params 可以接收到传递过来的paramas参数
*/
}
const findResult = DetailData.find(item => {
return item.id === id
})
return (
<ul>
<li>ID:{id}</li>
<li>title:{title}</li>
<li>ID:{findResult.content}</li>
</ul>
)
}
}
传递search参数
总结
-
路由链接(携带参数):<Link to='/demo/test?name=tom&age=18'}>详情
-
注册路由(无需声明,正常注册即可):
-
接收参数:this.props.location.search,获取到的search是urlencoded编码字符串,需要借助querystring库解析
//home组件中
import React, { Component } from 'react'
import { Link, Route } from 'react-router-dom'
import Detail from './Detail'
export default class Message extends Component {
state = {
messageArr: [
{ id: '01', title: '消息1' },
{ id: '02', title: '消息2' },
{ id: '03', title: '消息3' }
]
}
render() {
const { messageArr } = this.state
return (
<div>
<ul>
{messageArr.map(msgObj => {
return (
<li key={msgObj.id}>
{/* 向路由组件传递search参数 */}
<Link to={`/home/detail/?id=${msgObj.id}&title=${msgObj.title}`}>
{msgObj.title}
</Link>
</li>
)
})}
</ul>
<hr />
{/* search参数无需声明接收,正常注册路由即可 */}
<Route path='/home/detail' component={Detail} />
</div>
)
}
}
//detail组件中
import React, { Component } from 'react'
import qs from 'querystring'
const DetailData = [
{ id: '01', content: '你好,中国' },
{ id: '02', content: '你好,尚硅谷' },
{ id: '03', content: '你好,未来的自己' }
]
export default class Detail extends Component {
render() {
console.log(this.props)
// 接收search参数
const { search } = this.props.location
const { id, title } = qs.parse(search.slice(1))
{/*
在路由组件中,this.props.loaction.search获得到的是形如 ?id=01&title='消息1'的
数据
urlencoded格式:id=01&title='消息1'
querystring库可以处理urlencoded格式
qs.parse(需要转化urlencoded的数据)===>转化为对象格式
qs.stringfy(需要转化对象的数据)===>转化为urlencoded格式
*/}
const findResult = DetailData.find(detailObj => {
return detailObj.id === id
})
return (
<ul>
<li>ID:{id}</li>
<li>TITLE:{title}</li>
<li>CONTENT:{findResult.content}</li>
</ul>
)
}
}
传递state参数
总结
-
路由链接(携带参数):<Link to={{pathname:'/demo/test',state:{name:'tom',age:18}}}>详情
-
注册路由(无需声明,正常注册即可):
-
接收参数:this.props.location.state,刷新也不会丢失数据
//home组件
import React, { Component } from 'react'
import { Link, Route } from 'react-router-dom'
import Detail from './Detail'
export default class Message extends Component {
state = {
messageArr: [
{ id: '01', title: '消息1' },
{ id: '02', title: '消息2' },
{ id: '03', title: '消息3' }
]
}
render() {
const { messageArr } = this.state
return (
<div>
<ul>
{messageArr.map(msgObj => {
return (
<li key={msgObj.id}>
{/* 向路由组件传递state参数,Link的to属性要写成对象形式 */}
<Link
to={{
pathname: '/home/detail',
state: { id: msgObj.id, title: msgObj.title }
}}
>
{msgObj.title}
</Link>
</li>
)
})}
</ul>
<hr />
{/* state参数无需声明接收,正常注册路由即可 */}
<Route path="/home/message/detail" component={Detail} />
</div>
)
}
}
//detail组件中接收数据
import React, { Component } from 'react'
const DetailData = [
{ id: '01', content: '你好,中国' },
{ id: '02', content: '你好,尚硅谷' },
{ id: '03', content: '你好,未来的自己' }
]
export default class Detail extends Component {
render() {
// 接收state参数
const { id, title } = this.props.location.state || {}
const findResult =
DetailData.find(detailObj => {
return detailObj.id === id
}) || {}
return (
<ul>
<li>ID:{id}</li>
<li>TITLE:{title}</li>
<li>CONTENT:{findResult.content}</li>
</ul>
)
}
}
编程式路由导航
路由组件
路由组件的props对象上有history对象,history身上有很多API可以实现路由跳转
-
this.prosp.history.push(path, state),同样可以传递 params,search,state数据
-
this.prosp.history.replace(path, state),同样可以传递 params,search,state数据
-
this.prosp.history.goBack()
-
this.prosp.history.goForward()
-
this.prosp.history.go()
一般组件
react-router-dom库中有个withRouter方法,可以将一般组件的props添加上路由组件身上所有的那些属性,如下,可以通过 this.props.history调用API 实现条状路由

import React, { Component } from 'react'
import { withRouter } from 'react-router-dom'
class Header extends Component {
back = () => {
this.props.history.goBack()
}
forward = () => {
this.props.history.goForward()
}
go = () => {
this.props.history.go(-2)
}
render() {
console.log('Header组件收到的props是', this.props);
return (
<div className="page-header">
<h2>React Router Demo</h2>
<button onClick={this.back}>回退</button>
<button onClick={this.forward}>前进</button>
<button onClick={this.go}>go</button>
</div>
)
}
}
export default withRouter(Header)
//withRouter可以加工一般组件,让一般组件具备路由组件所特有的API
//withRouter的返回值是一个新组件
BrowerRouter和HashRouter的区别
-
底层原理不一样:
- BrowserRouter使用的是H5的history API,不兼容IE9及以下版本。
- HashRouter使用的是URL的哈希值。
-
path表现形式不一样
- BrowserRouter的路径中没有#,例如:localhost:3000/demo/test
- HashRouter的路径包含#,例如:localhost:3000/#/demo/test
-
刷新后对路由state参数的影响
- BrowserRouter没有任何影响,因为state保存在history对象中。
- HashRouter刷新后会导致路由state参数的丢失!!!
-
备注:HashRouter可以用于解决一些路径错误相关的问题。
组件懒加载
-
通过React的lazy函数配合import()函数动态加载路由组件 ===> 路由组件代码会被分开打包const Login = lazy(()=>import('@/pages/Login'))
-
通过
指定在加载得到路由打包文件前显示一个自定义loading界面
<Suspense fallback={}>
<Switch>
<Route path="/xxx" component={Xxxx}/>
<Redirect to="/login"/>
</Switch>
</Suspense>
import React, { Component, lazy, Suspense } from 'react'
import { NavLink, Route } from 'react-router-dom'
import Loading from './Loading'
//1.引入组件时要用lazy函数引入
const Home = lazy(() => import('./Home'))
const About = lazy(() => import('./About'))
export default class Demo extends Component {
render() {
return (
<div>
<div className="list-group">
{/* 在React中靠路由链接实现切换组件--编写路由链接 */}
<NavLink className="list-group-item" to="/about">About</NavLink>
<NavLink className="list-group-item" to="/home">Home</NavLink>
</div>
<div>
<Suspense fallback={<Loading />}>
//需要懒加载的组件需要用Supense标签包裹,并通过fallback指定一个组件或者DOM,
表示当懒加载的组件没有请求回来时展示的内容
{/* 注册路由 */}
<Route path="/about" component={About} />
<Route path="/home" component={Home} />
</Suspense>
</div>
</div>
)
}
}

浙公网安备 33010602011771号