文章目录
1、理解
2、react-router-dom相关API
3、基本路由使用
4、嵌套路由使用(二级/多级路由)
5、向路由组件传递参数数据
6、编程式路由导航
7、withRouter的使用
8、BrowserRouter和HashRouter
一、理解
1、SPA页面
- 单页web应用,simple page application
- 整个页面只有一个html页面
- 点击页面中的链接不会刷新页面,只会做页面的局部更新
- 数据都需要通过ajax请求获取, 并在前端异步展现
2、路由
一个路由就是一个key-value的映射关系,key为路径,value可能是function或component。
分类:
-
后端路由
- value是function,用来解决客户端发出的请求
- 注册路由:router.get(path, function(req, res))
- 工作过程:当node接收到一个请求时, 根据请求路径找到匹配的路由, 调用路由中的函数来处理请求, 返回响应数据
-
前端路由(浏览器端路由)
-
value是component,用来展示页面内容
-
注册路由:
-
工作过程:当浏览器的path变为/test时, 当前路由组件就会变为Test组件
-
实现原理:利用BOM的history对象
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>前端路由的基石_history</title> </head> <body> <a href="http://www.atguigu.com" onclick="return push('/test1') ">push test1</a><br><br> <button onClick="push('/test2')">push test2</button><br><br> <button onClick="replace('/test3')">replace test3</button><br><br> <button onClick="back()"><= 回退</button> <button onClick="forword()">前进 =></button> <script type="text/javascript" src="https://cdn.bootcss.com/history/4.7.2/history.js"></script> <script type="text/javascript"> // let history = History.createBrowserHistory() //方法一,直接使用H5推出的history身上的API let history = History.createHashHistory() //方法二,hash值(锚点) function push (path) { history.push(path) return false; // 不会跳转到新页面 } function replace (path) { history.replace(path) } function back() { history.goBack() } function forword() { history.goForward() } history.listen((location) => { console.log('请求路由路径变化了', location) }) </script> </body> </html>
-
3、 react-router-dom的理解
- react的一个插件库
- 专门用来实现一个SPA应用
- 基于react项目基本都会用到此库
印记中文:网站,可找到很多前端的英文文档翻译为中文的
二、react-router-dom相关API
简单了解下
1、内置组件
- BrowserRouter
- HashRouter
- Route
- Redirect
- Link
- NavLink
- Switch
2、其他
- history对象
- match对象
- withRouter函数
三、基本路由使用
1、准备
下载react-router-dom: npm install --save react-router-dom
2、简单使用例子
// index.js
import App from './App'
import {
BrowserRouter} from 'react-router-dom'
ReactDOM.render(
{
/* 直接在最外层包一个路由器,防止子组件内出现多个而不是同个路由器,无法跳转 */}
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
)
// app.jsx
import React, {
Component} from 'react'
import {
BrowserRouter, Link, NavLink, Route} from 'react-router-dom'
import Home from './page/Home'
import About from './page/About'
export default class app extends Component {
render() {
return (
<div>
<div className="row">
<div className="col-xs-offset-2 col-xs-8">
<div className="page-header"><h2>React Router Demo</h2></div>
</div>
</div>
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
{
/* 原生html中,靠<a>跳转不同的页面 */}
{
/*<a className="list-group-item active" href="./about.html">About</a>
<a className="list-group-item" href="./home.html">Home</a> */}
{
/* 在React靠路由链接实现切换组件--编写路由链接 */}
{
/* 一定不能在编写路由链接和注册路由,分别包一个<BrowserRouter>组件,防止不是同个路由器而无法跳转 */}
<Link className="list-group-item" to="/about">About</Link>
<Link className="list-group-item" to="/home">Home</Link>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
{
/* 注册路由 */}
<Route path='/about' componet={
About}/>
<Route path='/home' componet={
Home}/>
</div>
</div>
</div>
</div>
</div>
)
}
}
// 组件home
import React, {
Component} from 'react'
export default class Home extends Component {
render() {
return <h3>这是一个Home页面</h3>
}
}
// 组件about
import React, {
Component} from 'react'
export default class About extends Component {
render() {
return <h3>这是一个About页面</h3>
}
}
NavLink组件和Link组件(都是编写路由链接,区别再于点击选中是否可有高亮的自定义样式)
{/* Link是最基本的路由链接 */}
<Link class="list-group-item" to="/about">About</Link>
<Link class="list-group-item" to="/home">Home</Link>
{/* Link是最基本的路由链接;若想点击有不同样式的需采用NavLink,点击默认会加样式名为active,或加个activeClassName的属性来定义点击后的样式名 */}
<NavLink activeClassName="active" class="list-group-item" to="/about">About</NavLink>
<NavLink activeClassName="active" class="list-group-item" to="/home">Home</NavLink>
Switch组件(放在注册路由的外层,用于检索到指定路由后就停止,不再全部路由全都检索一遍)
{/* 在外面包一层switch组件 */}
<Switch>
<Route path='/about' componet={About}/>
<Route path='/home' componet={Home}/>
</Switch>
3、总结
- 明确好页面的导航区、展示区
- 导航区中的a标签改为Link标签:Demo
- 展示区去写Route标签进行路径的匹配:
- App的最外侧包裹一个或
- Route的外层可包裹一个Switch,按顺序检索到所指定的路由,就不继续往下检索其他的路由。当路由过多的话 ,每次更改一次就要全部去匹配一次,效率低。
4、路由组件和一般组件
-
写法不同
一般组件:
路由组件:
-
存放位置不同
一般组件:components文件夹
路由组件:page文件夹
-
接收的props不同
一般组件:写组件标签时传递了什么,就能收到什么
路由组件:接收到3个固定的属性,如下所示
- history
- go: f go(n)
- goBack: f goBack()
- goForward: f goForward()
- push: f push(path, state)
- replace: f replace(path, state)
- location
- pathname: “/about”
- search: “”
- state: undefined
- match
- params: {}
- path: “/about”
- url: “/about”
- history
5、解决多级路径刷新页面样式丢失的问题
- public/index.html中,引入样式时,不写 ./ ,写 / (常用)
- public/index.html中,引入样式时,不写 ./ ,写 %PUBLICK_URL% (常用)
- 使用HashRouter,浏览器路径会加#,#号后面的路径是不带到服务器上的
6、路由的模糊匹配与严格匹配exact
{/* 编写路由链接 */}
<Link class="list-group-item" to="/home/a/b/c">Home</Link>
{/* 注册路由 */}
<Route path='/home' componet={Home}/>
{/* 模糊匹配(默认),只要路由链接路径的前面部分,存在同注册路由一样的,是会匹配上的 */}
{/* 开启严格匹配,Route加个属性 exact={true} */}
<Route exact={true} path='/home' componet={Home}/>
<Route exact path='/home' componet={Home}/>
- 默认使用的是模糊匹配(简单记:【输入的路径】必须包含【要匹配的路径】,且舒徐要一致)
- 开启严格匹配:
- 严格匹配不要随便开启,需要再开启,有时候开启会导致无法继续匹配二级路由
7、Redirct的使用
{/* 谁都匹配不上的时候,跳转到Redirct指定的路由 */}
<Route path='/about' componet={About}/>
<Route path='/home' componet={Home}/>
<Redirct to="/about" />
8、push与replace
默认路由跳转是:push,会留下记录,入栈history
而replace是替换,不留下记录,替换栈顶
<Route path='/about' componet={
About}/>
// 开启replace
<Route replace={
true} path='/about' componet={
About}/>
四、嵌套路由使用(二级/多级路由)
前提代码
// index.js
import App from './App'
import {
BrowserRouter} from 'react-router-dom'
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
)
// app.jsx
import React, {
Component} from 'react'
import {
BrowserRouter, Link, NavLink, Route} from 'react-router-dom'
import Home from './page/Home'
import About from './page/About'
export default class app extends Component {
render(){
retrun(
<div>
<div className="row">
<div className="col-xs-offset-2 col-xs-8">
<div className="page-header"><h2>React Router Demo</h2></div>
</div>
</div>
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
{
/* 编写路由链接 */}
<NavLink activeClassName="active" class="list-group-item" to="/about">About</NavLink>
<NavLink activeClassName="active" class="list-group-item" to="/home">Home</NavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
{
/* 注册路由 */}
<Switch>
<Route path='/about' componet={
About}/>
<Route path='/home' componet={
Home}/>
<Redirct to="/about" />
</Switch>
</div>
</div>
</div>
</div>
</div>
)
}
}
// 组件about
import React, {
Component} from 'react'
export default class About extends Component {
render() {
return <h3>这是一个About页面</h3>
}
}
1、使用示例
// 组件home
import React, {
Component} from 'react'
import {
NavLink, Route } from 'react-router-dom'
import Message from './page/Home/Message'
import News from './page/News'
export default class Home extends Component {
render(){
return(
<h3>这是一个Home页面</h3>
<div>
<ul className="nav-nav-tabs">
{
/* 编写路由链接 */}
<li>
<NavLink activeClassName="active" class="list-group-item" to="/home/news">News</NavLink>
</li>
<li>
<NavLink activeClassName="active" class="list-group-item" to="/home/message">Message</NavLink>
</li>
</ul>
{
/* 注册路由 */}
<Switch>
<Route path='/home/news' componet={
News}/>
<Route path='/home/message' componet={
Message}/>
<Redirct to="/home/news" />
</Switch>
</div>
)
}
}
// 组件Message
import React, {
Component} from 'react'
export default class Message extends Component {
render(){
<h3>这是一个Message组件</h3>
}
}
// 组件News
import React, {
Component} from 'react'
export default class News extends Component {
render(){
<h3>这是一个News组件</h3>
}
}
2、总结
- 注册子路由时要写上父路由的path
- 路由的匹配时按照注册路由的顺序进行的
五、向路由组件传递参数数据
前提代码
// index.js
import App from './App'
import {
BrowserRouter} from 'react-router-dom'
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
)
// app.jsx
import React, {
Component} from 'react'
import {
BrowserRouter, Link, NavLink, Route} from 'react-router-dom'
import Home from './page/Home'
import About from './page/About'
export default class app extends Component {
render() {
return(
<div>
<div className="row">
<div className="col-xs-offset-2 col-xs-8">
<div className="page-header"><h2>React Router Demo</h2></div>
</div>
</div>
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
{
/* 编写路由链接 */}
<NavLink activeClassName="active" class="list-group-item" to="/about">About</NavLink>
<NavLink activeClassName="active" class="list-group-item" to="/home">Home</NavLink>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
{
/* 注册路由 */}
<Switch>
<Route path='/about' componet={
About}/>
<Route path='/home' componet={
Home}/>
<Redirct to="/about" />
</Switch>
</div>
</div>
</div>
</div>
</div>
)
}
}
// 组件about
import React, {
Component} from 'react'
export default class About extends Component {
render(){
<h3>这是一个About页面</h3>
}
}
// 组件home
import React, {
Component} from 'react'
import {
NavLink, Route } from 'react-router-dom'
import Message from './page/Home/Message'
import News from './page/News'
export default class Home extends Component {
render() {
retrun (
<h3>这是一个Home页面</h3>
<div>
<ul className="nav-nav-tabs">
{
/* 编写路由链接 */}
<li>
<NavLink activeClassName="active" class="list-group-item" to="/home/news">News</NavLink>
</li>
<li>
<NavLink activeClassName="active" class="list-group-item" to="/home/message">Message</NavLink>
</li>
</ul>
{
/* 注册路由 */}
<Switch>
<Route path='/home/news' componet={
News}/>
<Route path='/home/message' componet={
Message}/>
<Redirct to="/home/news" />
</Switch>
</div>
)
}
}
// 组件News
import React, {
Component} from 'react'
export default class News extends Component {
render() {
return <h3>这是一个News组件</h3>
}
}
1、params参数例子
// 组件Message
import React, {
Component} from 'react'
import {
Link, Route} from 'react-router-dom'
import Detail from './page/Home/Message/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}>
{
/* 向路由组件传递params参数 */}
<Link class="list-group-item" to={
`/home/message/detail/${
msgObj.id}/${
msgObj.title}`}>{
msgObj.title}</Link>
</li>
)
})
}
</ul>
<hr />
{
/* 声明接收params参数 */}
<Route path="/home/message/detail/:id/:title" component={
Detail} />
</div>
)
}
}
// 组件Detail
import React, {
Component} from 'react'
export default class Detail extends Component {
state = {
messageArr: [
{
id:'01', content:'内容1'},
{
id:'02', content:'内容2'},
{
id:'03', content:'内容3'},
]
}
render(){
// 接收params参数
const {
id, title } = this.props.match.params;
const currentObj = this.state.messageArr.find((obj) => {
return obj.id = id;
})
return (
<ul>
<li>ID:{
id}</li>
<li>TITLE:{
title}</li>
<li>CONTENT:{
currentObj.content}</li>
</ul>
)
}
}
2、search参数例子
// 组件Message
import React, {
Component} from 'react'
import qs from 'querystring'
import {
Link, Route} from 'react-router-dom'
import Detail from './page/Home/Message/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}>
{
/* 向路由组件传递params参数 */}
{
/* <Link class="list-group-item" to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link> */}
{
/* 向路由组件传递search参数 */}
<Link class="list-group-item" to={
`/home/message/detail?id=${
msgObj.id}&title=${
msgObj.title}`}>{
msgObj.title}</Link>
</li>
)
})
}
</ul>
<hr />
{
/* 声明接收params参数 */}
{
/* <Route path="/home/message/detail/:id/:title" component={Detail} /> */}
{
/* search参数无需声明接收,正常注册即可 */}
<Route path="/home/message/detail" component={
Detail} />
</div>
)
}
}
// 组件Detail
import React, {
Component} from 'react'
export default class Detail extends Component {
state = {
messageArr: [
{
id:'01', content:'内容1'},
{
id:'02', content:'内容2'},
{
id:'03', content:'内容3'},
]
}
render(){
// 接收params参数
// const { id, title } = this.props.match.params;
// 接收search参数
const {
search } = this.props.location;
const {
id, title } = qs.parse(search.silce(1));
const currentObj = this.state.messageArr.find((obj) => {
return obj.id = id;
})
retrun (
<ul>
<li>ID:{
id}</li>
<li>TITLE:{
title}</li>
<li>CONTENT:{
currentObj.content}</li>
</ul>
)
}
}
urlencoded => key=value&key=value
react可借助querystring库去解析地址参数
import qs from 'querystring';
let obj = {
name: 'cyr', age: 18};
console.log(qs.stringfy(obj)); // 输出结果:name=cyr&age=18
let str = 'name=cyr&age=18';
console.log(qs.parse(str)); // 输出结果: Object{name: 'cyr', age: 18}
3、state参数
// 组件Message
import React, {
Component} from 'react'
// import qs from 'querystring'
import {
Link, Route} from 'react-router-dom'
import Detail from './page/Home/Message/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;
retrun (
<div>
<ul>
{
messageArr.map((msgObj) => {
return(
<li key={
msgObj}>
{
/* 向路由组件传递params参数 */}
{
/* <Link class="list-group-item" to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link> */}
{
/* 向路由组件传递search参数 */}
{
/* <Link class="list-group-item" to={`/home/message/detail?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link> */}
{
/* 向路由组件传递state参数 */}
<Link class="list-group-item" to={
{
pathname:'/home/message/detail', state:{
id: msgObj.id, title: msgObj.title}}}>{
msgObj.title}</Link>
</li>
)
})
}
</ul>
<hr />
{
/* 声明接收params参数 */}
{
/* <Route path="/home/message/detail/:id/:title" component={Detail} /> */}
{
/* search参数无需声明接收,正常注册即可 */}
{
/* <Route path="/home/message/detail" component={Detail} /> */}
{
/* state参数无需声明接收,正常注册即可 */}
<Route path="/home/message/detail" component={
Detail} />
</div>
)
}
}
// 组件Detail
import React, {
Component} from 'react'
export default class Detail extends Component {
state = {
messageArr: [
{
id:'01', content:'内容1'},
{
id:'02', content:'内容2'},
{
id:'03', content:'内容3'},
]
}
render(){
// 接收params参数
// const { id, title } = this.props.match.params;
// 接收search参数
// const { search } = this.props.location;
// const { id, title } = qs.parse(search.silce(1));
// 接收state参数
const {
id, title } = this.props.location.state || {
};
const currentObj = this.state.messageArr.find((obj) => {
return obj.id = id;
}) || {
};
return (
<ul>
<li>ID:{
id}</li>
<li>TITLE:{
title}</li>
<li>CONTENT:{
currentObj.content}</li>
</ul>
)
}
}
4、总结
-
params参数:
(1)路由链接(携带参数):
<Link to='/home/message/detail/1/测试‘}>详情</Link>
(2)注册路由(声明接收):
<Route path='/home/message/detail/:id/:title' component={Detail} />
(3)接收参数:const { id, title } = this.props.match.params
-
search参数:
(1)路由链接(携带参数):
<Link to='/home/message/detail?id=1&title=测试‘}>详情</Link>
(2)注册路由(无需声明接收,正常注册即可):
<Route path='/home/message/detail' component={Detail} />
(3)接收参数:const { search } = this.props.location
(4)备注:获取到的search是urlencoded编码字符串,需要借助querystring解析
-
state参数:
(1)路由链接(携带参数):
<Link to={ {pathname:'/home/message/detail', state:{id: msgObj.id, title: msgObj.title}}}>详情</Link>
(2)注册路由(无需声明接收,正常注册即可):
<Route path='/home/message/detail' component={Detail} />
(3)接收参数:const { id, title} = this.props.location.state
(4)浏览器路由路劲未带所传的参数,刷新是否可读取到? 可以的,因参数是放在浏览器的history对象的state里面(其中 this.props.location同 this.props.history的location是同一个的);但浏览器清楚缓存后再访问页面,参数就读取不到
六、编程式路由导航
1、示例
// 组件Message
import React, {
Component} from 'react'
// import qs from 'querystring'
import {
Link, Route} from 'react-router-dom'
import Detail from './page/Home/Message/Detail'
export default class Message extends Component {
state = {
messageArr: [
{
id:'01', title:'消息1'},
{
id:'02', title:'消息2'},
{
id:'03', title:'消息3'},
]
}
replaceShow = (id, title) => {
// replace跳转 + 携带params参数
this.props.history.replace(`/home/message/detail/${
id}/${
title}`);
// replace跳转 + 携带search参数
// this.props.history.replace(`/home/message/detail?id=${id}&title=${title}`);
// replace跳转 + 携带state参数
// this.props.history.replace('/home/message/detail', {id, title});
}
pushShow = (id, title) => {
// push跳转 + 携带params参数
this.props.history.push(`/home/message/detail/${
id}/${
title}`);
// push跳转 + 携带search参数
// this.props.history.push(`/home/message/detail?id=${id}&title=${title}`);
// push跳转 + 携带state参数
// this.props.history.push('/home/message/detail', {id, title});
}
back = () => {
this.props.history.goBack();
}
forward = () => {
this.props.history.goForward();
}
go = () => {
this.props.history.go(2);
}
render(){
const {
messageArr} = this.state;
return (
<div>
<ul>
{
messageArr.map((msgObj) => {
return(
<li key={
msgObj}>
{
/* 向路由组件传递params参数 */}
<Link class="list-group-item" to={
`/home/message/detail/${
msgObj.id}/${
msgObj.title}`}>{
msgObj.title}</Link>
{
/* 向路由组件传递search参数 */}
{
/* <Link class="list-group-item" to={`/home/message/detail?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link> */}
{
/* 向路由组件传递state参数 */}
{
/* <Link class="list-group-item" to={
{pathname:'/home/message/detail', state:{id: msgObj.id, title: msgObj.title}}}>{msgObj.title}</Link> */}
<button onClick={
() => this.pushShow(msgObj.id, msgObj.title)}>push查看</button>
<button onClick={
() => this.replaceShow(msgObj.id, msgObj.title)}>replace查看</button>
</li>
)
})
}
</ul>
<hr />
{
/* 声明接收params参数 */}
<Route path="/home/message/detail/:id/:title" component={
Detail} />
{
/* search参数无需声明接收,正常注册即可 */}
{
/* <Route path="/home/message/detail" component={Detail} /> */}
{
/* state参数无需声明接收,正常注册即可 */}
{
/* <Route path="/home/message/detail" component={Detail} /> */}
<button onClick={
this.back}>回退</button>
<button onClick={
this.forward}>前进</button>
<button onClick={
this.go}>go前进/回退n步</button>
</div>
)
}
}
// 组件Detail
import React, {
Component} from 'react'
export default class Detail extends Component {
state = {
messageArr: [
{
id:'01', content:'内容1'},
{
id:'02', content:'内容2'},
{
id:'03', content:'内容3'},
]
}
render(){
// 接收params参数
const {
id, title } = this.props.match.params;
// 接收search参数
// const { search } = this.props.location;
// const { id, title } = qs.parse(search.silce(1));
// 接收state参数
// const { id, title } = this.props.location.state || {};
const currentObj = this.state.messageArr.find((obj) => {
return obj.id = id;
}) || {
};
return (
<ul>
<li>ID:{
id}</li>
<li>TITLE:{
title}</li>
<li>CONTENT:{
currentObj.content}</li>
</ul>
)
}
}
2、总结
借助this.props.history对象上的API对操作路由跳转、前进、后退
- this.props.history.push(path[, state])
- this.props.history.replace(path[, state])
- this.props.history.goBack()
- this.props.history.goForward()
- this.props.history.go(n)
七、withRouter的使用
如何让一般组件也能用上路由组件的方法?
前提代码
// index.js
import App from './App'
import {
BrowserRouter} from 'react-router-dom'
ReactDOM.render(
{
/* 直接在最外层包一个路由器,防止子组件内出现多个而不是同个路由器,无法跳转 */}
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
)
// app.jsx
import React, {
Component} from 'react'
import {
BrowserRouter, Link, NavLink, Route} from 'react-router-dom'
import Header from './component/Header'
import Home from './page/Home'
import About from './page/About'
export default class app extends Component {
render() {
retrun (
<div>
<div className="row">
<Header />
</div>
<div className="row">
<div className="col-xs-2 col-xs-offset-2">
<div className="list-group">
{
/* 原生html中,靠<a>跳转不同的页面 */}
{
/*<a className="list-group-item active" href="./about.html">About</a>
<a className="list-group-item" href="./home.html">Home</a> */}
{
/* 在React靠路由链接实现切换组件--编写路由链接 */}
{
/* 一定不能在编写路由链接和注册路由,分别包一个<BrowserRouter>组件,防止不是同个路由器而无法跳转 */}
<Link className="list-group-item" to="/about">About</Link>
<Link className="list-group-item" to="/home">Home</Link>
</div>
</div>
<div className="col-xs-6">
<div className="panel">
<div className="panel-body">
{
/* 注册路由 */}
<Route path='/about' componet={
About}/>
<Route path='/home' componet={
Home}/>
</div>
</div>
</div>
</div>
</div>
)
}
}
// 组件home
import React, {
Component} from 'react'
export default class Home extends Component {
render() {
return <h3>这是一个Home页面</h3>
}
}
// 组件about
import React, {
Component} from 'react'
export default class About extends Component {
render() {
return <h3>这是一个About页面</h3>
}
}
1、示例
// 一般组件Header
import React, {
Component} from 'react'
import {
withRouter} from 'react-router-dom'
class Header extends Componet {
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="col-xs-offset-2 col-xs-8">
<div className="page-header"><h2>React Router Demo</h2></div>
<button onClick={
this.back}>回退</button>
<button onClick={
this.forward}>前进</button>
<button onClick={
this.go}>go前进/回退n步</button>
</div>
)
}
}
export defalut withRouter(Header)
2、总结
- withRouter是个函数
- withRouter可以加工一般组件,让一般组件具备路由组件所持有的API
- withRouter的返回值是一个新组件
八、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参数丢失