React路由
1、SPA应用
- 单页面多组件应用
- 整个应用只有一个完整的页面
- 点击页面中的链接不会刷新页面,只会做页面的局部更新
- 数据都需要通过ajax请求获取,并在前端异步展现
2、路由理解
2.1、什么是路由
- 路由就是一组映射关系,key就是路径,value对应的就是一个一个函数或者组件
2.2、路由分类
- 路由分为前端路由和后端路由
- 后端路由对应的就是请求的接口地址
- 前端路由就是对应的导航栏的地址,一个地址对应一个页面或者组件
- 前端路由又分为两种:
Hash路由、history路由
- Hash路由:会在地址栏后面拼接
#/xxx/xxx
,兼容性最好,但是地址栏不美观- history路由:由
H5
新推出的windows
上自带的API
,地址栏干净,但是兼容性没有上面的好
3、react-router-dom
react-router
推出了三款根据不同平台的路由,这里主要演示web,any东西太杂,不容易理解
- web
- native
- any,上面都可以用的
3.1、安装
// 这里安装的 5 的版本
npm i react-router-dom@5
3.2、基本使用
BrowserRouter
组件:应该放到index.js
的<App />
外侧,这样App
中的所有路由皆是同一个映射关系
。一个BrowserRouter
标签内的Link、Route
为同一组Map
映射,两组不同的映射之间无法关联,所以一般会在<App />
最外侧放置一个即可HashRouter
组件:与上面用法一直,只不过是Hash路由的方式Link
组件:组件中的to
属性绑定一个地址(前面不能加.
)用于定义映射关系中的key
属性,渲染到页面上的时候,会渲染为a
标签,并且to
属性的值会被转为a
标签上的href
属性Route
组件:组件中的path
属性对应上面定义的key
,component
属性对应一个组件,即value
- 还有其他组件,可自行去官网查看…
下面使用一个案例来演示使用
BrowserRouter
效果
HashRouter
效果
index.js
import React from "react";
import ReactDOM from "react-dom/client";
// 引入 BrowserRouter: history路由 HashRouter:hash路由 组件
import { BrowserRouter, HashRouter } from "react-router-dom";
import "./index.css";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
// 包裹在最外侧
<BrowserRouter>
<React.StrictMode>
<App />
</React.StrictMode>
</BrowserRouter>
);
App.jsx
import React, { Component } from "react";
import { Link, Route} from "react-router-dom";
import About from "./components/About";
import Home from "./components/Home";
import "./App.css"
export default class App extends Component {
render() {
return <div className="app">
<h1>React Router Dom</h1>
<div className="main">
<div className="leftToolBar">
<Link to="/home" className="link">Home</Link>
<Link to="/about" className="link">About</Link>
</div>
<div className="rightContent">
<Route path="/home" component={Home} />
<Route path="/about" component={About} />
</div>
</div>
</div>;
}
}
App.css
.app {
margin-left: 20vw;
}
.app .main {
display: flex;
column-gap: 30px;
}
.app .leftToolBar {
display: flex;
flex-direction: column;
}
.app .leftToolBar .link {
padding: 6px 20px;
border: 1px solid #000;
border-radius: 4px;
}
.app .leftToolBar .link:focus {
background-color: gray;
color: #fff;
}
About&Home
4、高级使用
4.1、一般组件与路由组件
- 上面的
Home、About
两个组件就是路由组件,咱们上面演示的组件Search、List
就是一般组件- 区别:
- 写法不同
- 一般组件:
<Demo/>
- 路由组件:
<Route path="/demo" component={Demo}/>
- 存放位置不同:
- 一般组件:
src/components
目录下- 路由组件:
src/pages
目录下- 接收到的props不同
- 一般组件:写组件标签时传递了什么,就能收到什么
- 路由组件:接收到三个固定的属性
- history:
- action:
"PUSH"
- block:
ƒ block(prompt)
- createHref:
ƒ createHref(location)
- *go:
ƒ go(n)
- ==*==goBack:
ƒ goBack()
- *goForward:
ƒ goForward()
- length:
6
- listen:
ƒ listen(listener)
- location:
{pathname: '/home', search: '', hash: '', state: undefined, key: '1ahhdt'}
- *push:
ƒ push(path, state)
- ==*==replace:
ƒ replace(path, state)
- location:
- hash:
""
- key:
"1ahhdt"
- *pathname:
"/home"
- *search:
""
- *state:
undefined
- match:
- isExact:
true
- *params:
{}
- ==*==path:
"/home"
- ==*==url:
"/home"
4.2、NavLink路由激活样式
NavLink:
和Link
组件不同的是,如果当前路由和标签上的to
属性值一样的话,就会标签上添加一个默认名为active
的类名,用于给激活标签添加自定义样式- 如果想要修改默认激活样式名,在标签上添加属性
activeClassName="xxxx"
即可修改- 上面咱们是使用
:forcus
添加样式的,如果用户点了其他地方,那么样式就会丢失,下面咱们优化一下样式,以及把Link
组件换为NavLink
组件
App.css
.app {
margin-left: 20vw;
}
.app .main {
display: flex;
column-gap: 30px;
}
.app .leftToolBar {
display: flex;
flex-direction: column;
}
.app .leftToolBar .link {
padding: 6px 20px;
border-radius: 4px;
border: 1px solid #000;
}
/* 激活样式 */
.app .leftToolBar .activeToolBar {
background-color: gray;
color: #fff;
}
App.jsx
import React, { Component } from "react";
import { NavLink, Route} from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
import "./App.css"
export default class App extends Component {
render() {
return <div className="app">
<h1>React Router Dom</h1>
<div className="main">
<div className="leftToolBar">
{/* 自定义激活样式类名, 将Link组件替换为NavLink组件 */}
<NavLink activeClassName="activeToolBar" to="/home" className="link">Home</NavLink>
<NavLink activeClassName="activeToolBar" to="/about" className="link">About</NavLink>
</div>
<div className="rightContent">
<Route path="/home" component={Home} />
<Route path="/about" component={About} />
</div>
</div>
</div>
}
}
4.3、优化NavLink
- 上面
NavLink
标签上,一般activeClassName、className
属性基本都是一样的,正常项目都会有很多页面,很多路由,写这么多难维护,所以咱们可以把公共的提取出来,封装成一个组件- 使用
this.props.children
即可获取父组件在子组件中传入的所有子元素!!
MyNavLink组件
import React, { Component } from "react";
import { NavLink, Route} from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
import "./App.css"
import MyNavLink from "./components/MyNavLink";
export default class App extends Component {
render() {
return <div className="app">
<h1>React Router Dom</h1>
<div className="main">
<div className="leftToolBar">
{/* 自定义激活样式类名, 将Link组件替换为NavLink组件 */}
{/* <NavLink activeClassName="activeToolBar" to="/home" className="link">Home</NavLink> */}
{/* <NavLink activeClassName="activeToolBar" to="/about" className="link">About</NavLink> */}
<MyNavLink to="/home">Home</MyNavLink>
{/* <MyNavLink to="/about">About</MyNavLink> */}
{/* 或者如下写法传入标签体 */}
<MyNavLink to="/about" children="About" />
</div>
<div className="rightContent">
<Route path="/home" component={Home} />
<Route path="/about" component={About} />
</div>
</div>
</div>
}
}
App组件
import React, { Component } from "react";
import { NavLink, Route} from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
import "./App.css"
import MyNavLink from "./components/MyNavLink";
export default class App extends Component {
render() {
return <div className="app">
<h1>React Router Dom</h1>
<div className="main">
<div className="leftToolBar">
{/* 自定义激活样式类名, 将Link组件替换为NavLink组件 */}
{/* <NavLink activeClassName="activeToolBar" to="/home" className="link">Home</NavLink> */}
{/* <NavLink activeClassName="activeToolBar" to="/about" className="link">About</NavLink> */}
<MyNavLink to="/home">Home</MyNavLink>
{/* <MyNavLink to="/about">About</MyNavLink> */}
{/* 或者如下写法传入标签体 直接在当做属性写 */}
<MyNavLink to="/about" children="About" />
</div>
<div className="rightContent">
<Route path="/home" component={Home} />
<Route path="/about" component={About} />
</div>
</div>
</div>
}
}
4.4、Switch组件
- 这里我们再写一个测试的路由组件,并且配置和
/about
一样的key
,不一样的value
路由组件- 结果是两个组件都会被渲染出来,这就证明了,匹配路由的时候,是从上往下一个一个匹配,如果匹配成功,依旧会往下继续匹配
- 那么,我们可以在外面套一层
Switch
组件,这样在匹配到一个的时候,不会继续往下匹配了,这样可以提高性能!
没有Switch
组件时
import React, { Component } from "react";
import { NavLink, Route} from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
import Test from "./pages/Test";
import "./App.css"
import MyNavLink from "./components/MyNavLink";
export default class App extends Component {
render() {
return <div className="app">
<h1>React Router Dom</h1>
<div className="main">
<div className="leftToolBar">
{/* 自定义激活样式类名, 将Link组件替换为NavLink组件 */}
{/* <NavLink activeClassName="activeToolBar" to="/home" className="link">Home</NavLink> */}
{/* <NavLink activeClassName="activeToolBar" to="/about" className="link">About</NavLink> */}
<MyNavLink to="/home">Home</MyNavLink>
{/* <MyNavLink to="/about">About</MyNavLink> */}
{/* 或者如下写法传入标签体 */}
<MyNavLink to="/about" children="About" />
</div>
<div className="rightContent">
<Route path="/home" component={Home} />
<Route path="/about" component={About} />
<Route path="/about" component={Test} />
</div>
</div>
</div>
}
}
有Switch
组件时
import React, { Component } from "react";
import { Route, Switch} from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
import Test from "./pages/Test";
import "./App.css"
import MyNavLink from "./components/MyNavLink";
export default class App extends Component {
render() {
return <div className="app">
<h1>React Router Dom</h1>
<div className="main">
<div className="leftToolBar">
{/* 自定义激活样式类名, 将Link组件替换为NavLink组件 */}
{/* <NavLink activeClassName="activeToolBar" to="/home" className="link">Home</NavLink> */}
{/* <NavLink activeClassName="activeToolBar" to="/about" className="link">About</NavLink> */}
<MyNavLink to="/home">Home</MyNavLink>
{/* <MyNavLink to="/about">About</MyNavLink> */}
{/* 或者如下写法传入标签体 */}
<MyNavLink to="/about" children="About" />
</div>
<div className="rightContent">
<Switch>
<Route path="/home" component={Home} />
<Route path="/about" component={About} />
<Route path="/about" component={Test} />
</Switch>
</div>
</div>
</div>
}
}
4.5、样式丢失问题
- 想要实现效果,我们需要把
app.css
移动到public/css/App.css
这里,然后在public/index.html
里面使用link
引入改样式,<link rel="stylesheet" href="./css/App.css" />
,最后把App.jsx
里面引入App.css
的样式注释掉即可- 假设我们要给原来的
key
前面添加一个/test
,这样路由地址就变为了/test/home
App.jsx
import React, { Component } from "react";
import { Route, Switch} from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
import MyNavLink from "./components/MyNavLink";
export default class App extends Component {
render() {
return <div className="app">
<h1>React Router Dom</h1>
<div className="main">
<div className="leftToolBar">
<MyNavLink to="/test/home">Home</MyNavLink>
{/* 或者如下写法传入标签体 */}
<MyNavLink to="/test/about" children="About" />
</div>
<div className="rightContent">
<Switch>
<Route path="/test/home" component={Home} />
<Route path="/test/about" component={About} />
</Switch>
</div>
</div>
</div>
}
}
- 然后点击路由,可以发现没有什么问题,地址栏也会改变,但是当我们点完路由点击浏览器左上角刷新时,就会发现样式丢失了
- 这时候咱们点开控制台的
网络
,然后查看App.css
请求,可以发现是200
,但是响应结果并不是对应的css
,而是index.html
- 这时候再看一下这个请求的请求地址
http://localhost:3000/test/css/App.css
,就会发现地址中多了一个/test
,去掉就没问题了- 原因:
- 当你访问了一个不存在的地址时,脚手架就会自动返回
public
目录中的index.html
http://localhost:3000
内置服务器 就相当于public
目录,当路由出现多级路径,并且刷新后,样式就会丢失了- 咱们在
index.html
中的href
属性是使用相对路径引入的- 修改方法(三种)
- 把
href
地址中前面的.
去掉,改为href="/css/App.css"
即可- 把前面的
.
替换为%PUBLIC_URL%
,改为href="%PUBLIC_URL%/css/App.css"
即可- 使用
HashRouter
即可,在index.js
中,将BrowserRouter 改为 HashRouter
即可,因为==#后面的地址不作为请求地址识别==
4.6、精准匹配与模糊匹配
- 默认是模糊匹配:输入的路径必须包含匹配的路径,并且顺序必须一致
- 通过在
Route
标签上添加exact
属性,开启严格匹配,即输入路径必须和匹配路径完全一致
代码
import React, { Component } from "react";
import { Route, Switch} from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
import Test from "./pages/Test";
import MyNavLink from "./components/MyNavLink";
export default class App extends Component {
render() {
return <div className="app">
<h1>React Router Dom</h1>
<div className="main">
<div className="leftToolBar">
<MyNavLink to="/home/a/b">Home</MyNavLink>
<MyNavLink to="/a/about/b" children="About" />
<MyNavLink to="/a/b/test" children="Test" />
</div>
<div className="rightContent">
<Switch>
{/* 默认是模糊匹配,只要/home/a/b的第一个和path中的第一个相同,那么则可以匹配成功 */}
<Route path="/home" component={Home} />
{/* /a/about/b 的第一个为 a,但是path中的地址第一个为about,不符合,那么就不看后面了,直接匹匹配不到*/}
<Route path="/about" component={About} />
{/* 开启严格匹配 由于上面to属性的值和path一致,那么匹配成功*/}
<Route exact path="/a/b/test" component={About} />
</Switch>
</div>
</div>
</div>
}
}
效果
4.7、Redirect重定向组件
- 我们刚打开页面
http://localhost:3000/
的时候,什么也不展示,这是因为地址栏斜杠后面没有东西,获取到的是""
空串,路由中并没有空串对应的组件,所以什么也不展示- 那么我们可以使用
Redirect
组件,使用to
属性指定,当所有路由都没匹配到的时候,就会走这里前往默认的路由
App
import React, { Component } from "react";
import { Route, Switch} from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
import MyNavLink from "./components/MyNavLink";
import { Redirect } from "react-router-dom/cjs/react-router-dom.min";
export default class App extends Component {
render() {
return <div className="app">
<h1>React Router Dom</h1>
<div className="main">
<div className="leftToolBar">
<MyNavLink to="/home">Home</MyNavLink>
<MyNavLink to="/about" children="About" />
</div>
<div className="rightContent">
<Switch>
<Route path="/home" component={Home} />
<Route path="/about" component={About} />
{/* 如果上面路由都匹配不到,那么走下面的路由 */}
<Redirect to="/home" />
</Switch>
</div>
</div>
</div>
}
}
效果
5、嵌套路由
- 假设我们
About
组件中,也有一部分内容可以跟随路由跳转而变换,那么我们就要先成功匹配到About
路由,再成功匹配到About
路由下的子路由- 注意:外层路由一定不能开启严格模式,否则嵌套路由将会失效
- 下面,我使用一个案例,来给大家演示一下用法
效果
项目结构
About.jsx
import React, { Component } from 'react'
import { Route, Switch} from "react-router-dom";
import MyNavLink from "../../components/MyNavLink";
import News from "./News";
import Message from "./Message";
import { Redirect } from "react-router-dom/cjs/react-router-dom.min";
import './about.css'
export default class About extends Component {
render() {
return (
<div className='about'>
<h2>我是About组件</h2>
<div className="card">
<div className="card-item">
{/* 注意:这里要/about/news,而不是直接/news,这样才能先匹配到 about 路由,再匹配news路由 */}
<MyNavLink to="/about/news">News</MyNavLink>
</div>
<div className="card-item">
<MyNavLink to="/about/message">Message</MyNavLink>
</div>
</div>
<div className="content">
{/* 这里需要去定义路由对应组件,否则就会去 App.jsx 那里定义的找,找不到则会走兜底逻辑 /home */}
<Switch>
<Route path="/about/news" component={News} />
<Route path="/about/message" component={Message} />
{/* 记得这里也给个默认路由 */}
<Redirect to="/about/news" />
</Switch>
</div>
</div>
)
}
}
about.css
.about .card{
display: flex;
gap: 20px;
}
.about .card .card-item .link{
display: block;
border: 1px solid #000;
padding: 8px 10px;
border-radius: 5px;
}
.activeToolBar {
background-color: #ce801a;
color: #fff;
}
news.jsx
import React, { Component } from 'react'
export default class News extends Component {
render() {
return (
<div>News</div>
)
}
}
message.jsx
import React, { Component } from 'react'
export default class Message extends Component {
render() {
return (
<div>Message</div>
)
}
}
6、路由传参
- 假设我们跳转页面的时候,要把当前页面的数据带到下一个页面使用,就需要实现路由传参了
- 传参方式共有如下三种,有利有弊,自行选择即可
6.1、params传参
- 路由链接(携带参数):
<MyNavLink to="/about/news/张三/18">News</MyNavLink>
- 注册路由(声明接收):
<Route path="/about/news/:name/:age" component={News} />
- 接收参数:
this.props.match.params
About.jsx
import React, { Component } from 'react'
import { Route, Switch} from "react-router-dom";
import MyNavLink from "../../components/MyNavLink";
import News from "./News";
import Message from "./Message";
import { Redirect } from "react-router-dom/cjs/react-router-dom.min";
import './about.css'
export default class About extends Component {
render() {
return (
<div className='about'>
<h2>我是About组件</h2>
<div className="card">
<div className="card-item">
{/* 在路由地址中 使用 /张三/18 携带参数 */}
<MyNavLink to="/about/news/张三/18">News</MyNavLink>
</div>
<div className="card-item">
<MyNavLink to="/about/message/李四/20">Message</MyNavLink>
</div>
</div>
<div className="content">
<Switch>
{/* 注意:使用:xxxx 声明接收 */}
<Route path="/about/news/:name/:age" component={News} />
<Route path="/about/message/:name/:age" component={Message} />
{/* 记得这里也给个默认路由 */}
<Redirect to="/about/news" />
</Switch>
</div>
</div>
)
}
}
News.jsx
import React, { Component } from 'react'
export default class News extends Component {
render() {
console.log(this.props);
return (
<div>
<h1>News</h1>
<h2>姓名:{this.props.match.params.name}</h2>
<h2>年龄:{this.props.match.params.age}</h2>
</div>
)
}
}
Message.jsx
import React, { Component } from 'react'
export default class Message extends Component {
render() {
console.log(this.props);
return (
<div>
<h1>Message</h1>
<h2>姓名:{this.props.match.params.name}</h2>
<h2>年龄:{this.props.match.params.age}</h2>
</div>
)
}
}
效果
6.2、search传参
- 路由链接(携带参数):
<MyNavLink *to***=**"/about/news?name=张三&age=18">News</MyNavLink>
- 注册路由(声明接收):无需声明
- 接收参数:
this.props.location.search
About.jsx
import React, { Component } from 'react'
import { Route, Switch} from "react-router-dom";
import MyNavLink from "../../components/MyNavLink";
import News from "./News";
import Message from "./Message";
import { Redirect } from "react-router-dom/cjs/react-router-dom.min";
import './about.css'
export default class About extends Component {
render() {
return (
<div className='about'>
<h2>我是About组件</h2>
<div className="card">
<div className="card-item">
{/* 在路由地址中 使用 /?key=value&key2=value2 携带参数 */}
<MyNavLink to="/about/news?name=张三&age=18">News</MyNavLink>
</div>
<div className="card-item">
<MyNavLink to="/about/message?name=李四&age=20">Message</MyNavLink>
</div>
</div>
<div className="content">
<Switch>
<Route path="/about/news" component={News} />
<Route path="/about/message" component={Message} />
{/* 这里如果配置默认路由,组件内将会获取不到页面传参 */}
{/* <Redirect to="/about/news" /> */}
</Switch>
</div>
</div>
)
}
}
News.jsx
import React, { Component } from 'react'
function getQueryParams(searchUrl) {
const queryParams = new URLSearchParams(searchUrl);
const paramsObj = {};
for (const [key, value] of queryParams.entries()) {
paramsObj[key] = value;
}
return paramsObj;
}
export default class News extends Component {
state = {
urlParams: {},
}
componentDidMount() {
const params = getQueryParams(this.props.location.search)
this.setState({ urlParams: params })
}
render() {
const { name, age } = this.state.urlParams;
return (
<div>
<h1>News</h1>
<h2>姓名:{name}</h2>
<h2>年龄:{age}</h2>
</div>
)
}
}
Message.jsx
import React, { Component } from 'react'
function getQueryParams(searchUrl) {
const queryParams = new URLSearchParams(searchUrl);
const paramsObj = {};
for (const [key, value] of queryParams.entries()) {
paramsObj[key] = value;
}
return paramsObj;
}
export default class Message extends Component {
state = {
urlParams: {},
}
componentDidMount() {
const params = getQueryParams(this.props.location.search)
this.setState({ urlParams: params })
}
render() {
const { name, age } = this.state.urlParams;
return (
<div>
<h1>Message</h1>
<h2>姓名:{name}</h2>
<h2>年龄:{age}</h2>
</div>
)
}
}
效果
6.3、state传参
- 路由链接(携带参数):
<MyNavLink to={ {pathname: '/about/news', state: {name: '张三', age: 18}}}>News</MyNavLink>
- 注册路由(声明接收):无需声明
- 接收参数:
this.props.location.state
- 注意:
- 如果有默认路由,那么要处理一下参数接收为
null
的问题- 虽然地址栏上没有参数,但是刷新页面依旧会保留参数,因为他借助的
H5 的 history API
,但是当开无痕或者清除浏览器缓存后,则会丢失参数
About.jsx
import React, { Component } from 'react'
import { Route, Switch} from "react-router-dom";
import MyNavLink from "../../components/MyNavLink";
import News from "./News";
import Message from "./Message";
import { Redirect } from "react-router-dom/cjs/react-router-dom.min";
import './about.css'
export default class About extends Component {
render() {
return (
<div className='about'>
<h2>我是About组件</h2>
<div className="card">
<div className="card-item">
{/* 在路由地址中 传入对象形式,{pathname: '路由地址', state: {参数对象}} */}
<MyNavLink to={ {pathname: '/about/news', state: {name: '张三', age: 18}}}>News</MyNavLink>
</div>
<div className="card-item">
<MyNavLink to={{pathname: '/about/message', state: {name: '李四', age: 20}}}>Message</MyNavLink>
</div>
</div>
<div className="content">
<Switch>
<Route path="/about/news" component={News} />
<Route path="/about/message" component={Message} />
{/* 注意:如果这里给默认路由了,那么组件内 结构 this.props.location.state 将会报错, 因为 this.props.location.state 为 null */}
{/* <Redirect to="/about/news" /> */}
</Switch>
</div>
</div>
)
}
}
News.jsx
import React, { Component } from 'react'
export default class News extends Component {
render() {
const { name, age } = this.props.location.state
return (
<div>
<h1>News</h1>
<h2>姓名:{name}</h2>
<h2>年龄:{age}</h2>
</div>
)
}
}
Message.jsx
import React, { Component } from 'react'
export default class Message extends Component {
render() {
const { name, age } = this.props.location.state
return (
<div>
<h1>Message</h1>
<h2>姓名:{name}</h2>
<h2>年龄:{age}</h2>
</div>
)
}
}
效果
7、push、replace、goBack、goForward、go等方法
- 导航路由链其实就是一个
堆栈
的操作,当我们从一个地址,通过push
方法跳入到另一个地址中,就会往堆栈中添加一条记录- 我们上面写的,默认都为
push
的操作,下面我们演示其他一些操作堆栈记录的方法
7.1、push
- 点击
Link
标签跳转默认为push
路由操作- 向堆栈中添加一条记录
代码
<MyNavLink to="/home">Home</MyNavLink>
效果
7.2、replace
- 如果在
Link
组件上添加replace
属性,那么则会变为替换操作- 会将当前所在记录替换为新地址
代码
<MyNavLink replace to="/about" children="About" />
效果
7.3、goBack
- 路由往后退一格,回到上一个页面,并不会删除任何路由
- 没有对应组件配置,只能使用下方编程式路由跳转
7.4、goForward
- 路由往前进一格,前进到下一个页面,并不会删除任何路由
- 没有对应组件配置,只能使用下方编程式路由跳转
7.5、go
- 该方法提供一个参数,如果为正数,则前进参数的步数;如果为负数,则后退参数的步数
- 没有对应组件配置,只能使用下方[编程式路由跳转](
8、编程式路由跳转
- 上面我们演示了组件标签进行跳转,但是如果我想点击按钮后,打印一句话,然后再进行跳转,就不行了
react-router-dom
提供了一套API
用于操控路由跳转- 上面我们提取出来了
this.props
中默认有的几个history、loaction、match
等属性,react-router-dom
将提供给我们的API
放入了history
对象中- 有了
history
对象中的方法,我们就可以在自身的方法中编写任意逻辑,在任意时刻进行路由跳转
8.1、push
<button onClick={() => this.props.history.push('/about/news', {name: '张三', age: 18})}>push跳转到news</button>
8.2、replace
<button onClick={() => this.props.history.replace('/about/message', {name: '李四', age: 20})}>replace跳转到Message</button>
8.3、goBack
<button onClick={() => this.props.history.goBack()}>goBack回退</button>
8.4、goForward
<button onClick={() => this.props.history.goForward()}>goForward前进</button>
8.5、go
<button onClick={() => this.props.history.go(-1)}>go(-1)后退1步</button>
<button onClick={() => this.props.history.go(1)}>go(1)前进1步</button>
8.6、统一效果演示
9、withRouter
- withRouter是用来解决一般组件的
props
中没有history
对象操控路由的问题- 当我们想把那几个操作按钮提出来到标题下面的时候,因为标题在
App
组件中,那么按钮就需要移动到App
组件里- 当我们移动到组件中的时候,点击按钮,发现会报错,
this.props
为空对象,并没有history
属性- 这时候我们就需要借助
withRouter
,来封装一下自己的组件并且export default
暴露出自己被封装过的组件即可
9.1、代码
import React, { Component } from "react";
// 从这里引入 withRouter
import { Route, Switch, withRouter} from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
import MyNavLink from "./components/MyNavLink";
import { Redirect } from "react-router-dom/cjs/react-router-dom.min";
class App extends Component {
render() {
return <div className="app">
<h1>React Router Dom</h1>
<button onClick={() => this.props.history.goBack()}>goBack回退</button>
<button onClick={() => this.props.history.goForward()}>goForward前进</button>
<button onClick={() => this.props.history.go(-1)}>go(-1)后退1步</button>
<button onClick={() => this.props.history.go(1)}>go(1)前进1步</button>
<div className="main">
<div className="leftToolBar">
<MyNavLink to="/home">Home</MyNavLink>
<MyNavLink replace to="/about" children="About" />
</div>
<div className="rightContent">
<Switch>
<Route path="/home" component={Home} />
<Route path="/about" component={About} />
{/* 如果上面路由都匹配不到,那么走下面的路由 */}
<Redirect to="/home" />
</Switch>
</div>
</div>
</div>
}
}
// 将自己的组件交给 withRouter 包装,那么就可以使用 this.props.history
export default withRouter(App);
9.2、效果
10、BrowserRouter与HashRouter区别
- 底层原理不一样
BrowserRouter
使用的是H5的history API
,不兼容IE9
及以下版本兼容性HashRouter
使用的是URL
的哈希值- path表现形式不一样
BrowserRouter
的路径中没有#
,例如localhost:3000/about/message
HashRouter
的路径包含#
,例如localhost:3000/#/about/message
- 刷新后对路由state参数的影响
BrowserRouter
没有任何影响,因为state
保存在history
对象中HashRouter
刷新后会导致路由state
参数丢失- 备注:
HashRouter
可以用于解决一些路径错误相关的问题