react路由守护(React路由)
单页面应用spa
多页面应用是指每切换一个页面就是一个真正的html页面。
单页面应用是指整个应用只有一个完整的页面,点击页面中的链接不会刷新页面只会局部更新,并且数据都需要通过ajax请求获取,并在前端异步展示。单页面,多组件。
路由
路由是什么
什么是路由? —— Route
—个路由就是一个映射关系 ( key:value )
key为路径, value 可能是function(后端路由)或component(前端路由)路由分类 后端路由:
理解:value是function,用来处理客户端提交的请求。
注册路由: router.get(path, function(req, res))
工作过程:当node接收到一个请求时,根据请求路径找到匹配的路由,调用路
由中的函数来处理请求返回响应数据 前端路由:
浏览器端路由,value是component,用于展示页面内容。
注册路由:
工作过程:当浏览器的path变为/test时,当前路由组件就会变为Test组件 路由器 —— Router
路由器是用于管理路由的。React路由原理
路由匹配的是只是端口号后面的内容(/about、/history)。
点击页面选项路径改变
那么是如何实现一点击导航栏的选项浏览器地址栏中的路径就改变呢, 这就需要借助history实现。
浏览器的BOM身上有一个history,用于管理浏览器的路径、历史记录等。
但是BOM原生的history不好操作我们一般用一个封装好的库history.js,(该库实际上操作的也是BOM身上的history)引入: <script type="text/javascript" src="https://cdn.bootcss.com/history/4.7.2/history.js"></script>,使用:
引入: let history = History.createBrowserHistory() 推入 // 将路径放到历史记录history中 history.push(path) 替换 // 将路径放到历史记录history中 history.replace(path) 监听路径变化 // history的listen方法可以监听路径的修改 history.listen((location) => { console.log(请求路由路径变化了, location) }) 前进 history.goForward() 后退 history.goBack()history的数据结构是栈结构:
栈顶的路径就是当前页面显示的内容。History.createBrowserHistory()是使用的是h5身上的history方法,在某些旧的浏览器不支持。
可以使用: History.createHashHistory(),和createBrowserHistory的区别是路径中会多出一个 # ,虽然不好看但是兼容性特别好。History.createBrowserHistory():
History.createHashHistory():
路径改变页面变化
React会监听路径,当路径发生变化时,被前端路由器检测到,就会进行路由匹配重新渲染页面。
React路由的使用
React路由的实现需要借助react的路由插件库:react-router-dom, 专门用于实现SPA应用。
安装: npm i react-router-dom实现点击页面选项路径改变——编写路由链接
直接利用从 react-router-dom 库中引入的路由器Router和</Link>标签就可以实现:
import { BrowserRouter, Link } from react-router-dom <BrowserRouter> <Link className="list-group-item" to="/about">About</Link> <Link className="list-group-item" to="/home">Home</Link> </BrowserRouter>点击About浏览器的路径就变成 /about, 点击Home浏览器的路径就变成/home
有两种Router标签:
(最后在浏览器渲染的时候,Link标签实际上是会转换为a标签的)
根据路径显示组件 ——注册路由
直接利用从 react-router-dom 库中引入的路由Route 进行路由的注册:
import { Route } from react-router-dom {/* 注册路由 */} <Route path="/about" component={About}/> <Route path="/home" component={Home}/><Route > 也需要使用Router标签进行包裹,但是编写路由链接的路由器应该和注册路由的路由器是一个路由器才对,可以直接将<App/>组件使用Router标签包裹即可。
index.js
// 引入react核心库 import React from react // 引入ReactDOM import ReactDOM from react-dom // 引入路由组件 import { BrowserRouter } from react-router-dom // 引入App组件 import App from ./App // 渲染App到页面 ReactDOM.render( <BrowserRouter> <App/> </BrowserRouter>, document.getElementById(root))组件的分类——普通组件和路由组件
像上面的例子通过路由来使用组件:
普通组件和路由组件一个最大的区别就是,路由组件可以接收到路由器传递的参数。如当点击上述例子的About按钮时,接收到的参数为:
history :
go:可以穿参数n,表示前进或后退|n|步,n>0表示前进n步,n<0表示后退n步。
goBack:后退1步
goForward:前进1步
push:push路由
replace:replace路由
location:(和下面的这个location是同一个对象) location
pathname:获取路由路径
search:(存储swarch参数)
state:(存储state参数) match
params:(存储params参数)
path:获取路由路径
url:获取路由路径案例
实现效果:
代码:src/index.js
// 引入react核心库 import React from react // 引入ReactDOM import ReactDOM from react-dom // 引入路由组件 import { BrowserRouter } from react-router-dom // 引入App组件 import App from ./App // 渲染App到页面 ReactDOM.render( <BrowserRouter> <App/> </BrowserRouter>, document.getElementById(root))src/App.jsx
import React, { Component } from react import { Link, Route } from react-router-dom import About from ./pages/About import Home from ./pages/Home import Header from "./components/Header" export default class App extends Component { render() { return ( <div> <Header/> <div className="row"> <div className="col-xs-2 col-xs-offset-2"> <div className="list-group"> {/* 原生直接使用a标签进行切换 */} {/* <a className="list-group-item active" href="./about.html">About</a> <a className="list-group-item" href="./home.html">Home</a> */} {/* react中靠路由链接进行切换 */} {/* 有两种Router: <BrowserRouter> <HashRouter> 再Router标签中再使用Link进行路由 */} <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" component={About}/> <Route path="/home" component={Home}/> </div> </div> </div> </div> </div> ) } }page/About/index.jsx
import React, { Component } from react export default class About extends Component { render() { console.log("接收到参数:", this.props); return ( <div>About ... </div> ) } }page/Home/index.jsx
import React, { Component } from react export default class Home extends Component { render() { return ( <div>Home ... </div> ) } }components/Header/index.jsx
import React, { Component } from react export default class index extends Component { render() { return ( <div className="row"> <div className="col-xs-offset-2 col-xs-8"> <div className="page-header"><h2>React Router Demo</h2></div> </div> </div> ) } }实现选中高亮效果——NavLink
需要借助 <NavLink><NavLink/>实现, <NavLink> 标签配合 activeClassName=类名 实现,当点击该标签 该样式就会显示。
activeClassName=类名中的类名默认是active。
eg:
上述案例修改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 Header from "./components/Header" export default class App extends Component { render() { return ( <div> <Header/> <div className="row"> <div className="col-xs-2 col-xs-offset-2"> <div className="list-group"> <NavLink activeClassName=active className="list-group-item" to="/about">About</NavLink> <NavLink activeClassName=active className="list-group-item" to="/home">Home</NavLink> </div> </div> <div className="col-xs-6"> <div className="panel"> <div className="panel-body"> {/* 注册路由 */} <Route path="/about" component={About}/> <Route path="/home" component={Home}/> </div> </div> </div> </div> </div> ) } }效果:
注意:这里我在public文件夹中已经引入了bootstrap.css样式,所以会有样式效果
NavLink的封装
知识点:
组件标签的标签体中的内容会作为children属性传递给组件 在组件中通过children属性就可以指定标签体的内容。即:
App.jsx import React, { Component } from react import { Route } from react-router-dom import About from ./pages/About import Home from ./pages/Home import Header from "./components/Header" import MyNavLink from ./components/MyNavLink export default class App extends Component { render() { return ( <div> <Header/> <div className="row"> <div className="col-xs-2 col-xs-offset-2"> <div className="list-group"> {/* 标签体中的内容会作为children属性传递给组件 */} <MyNavLink to="/home">Home</MyNavLink> <MyNavLink to="/about">About</MyNavLink> </div> </div> <div className="col-xs-6"> <div className="panel"> <div className="panel-body"> {/* 注册路由 */} <Route path="/about" component={About}/> <Route path="/home" component={Home}/> </div> </div> </div> </div> </div> ) } }MyNavLink,jsx
import React, { Component } from react import { NavLink } from react-router-dom export default class MyNavLink extends Component { render() { return ( <NavLink activeClassName=active className="list-group-item" {...this.props}/> ) } }Switch的使用
一般情况下一个路径(path)只对应一个组件,如果一个路径对应多个组件会是什么效果呢,答案是多个组件都会显示,如:
<div className="col-xs-6"> <div className="panel"> <div className="panel-body"> {/* 注册路由 */} <Route path="/about" component={About}/> <Route path="/home" component={Home}/> <Route path="/home" component={Test}/> </div> </div> </div>显示如下:
说明当路径匹配完成之后如果再出现同样的路径就会再次匹配,但是一般情况下一个路径对应一个组件就可以了,所以说为了提升效率,我们希望当匹配到一个路径之后,再碰到该路径就不会进行匹配了。这就可以借助<Switch>组件,用<Switch>组件包裹路由。 import { Route, Switch } from react-router-dom <div className="col-xs-6"> <div className="panel"> <div className="panel-body"> {/* 注册路由 */} <Switch> <Route path="/about" component={About}/> <Route path="/home" component={Home}/> <Route path="/home" component={Test}/> </Switch> </div> </div> </div>补充:样式丢失问题
启动React脚手架,浏览器访问http://localhost:3000/favicon.ico,代表访问public文件夹下的favicon.ico资源。即本地服务器的根路径就是/public文件夹,如果/public文件夹中没有对应的资源就会返回/public/index.html内容。
当路由路径是多级路径,并且刷新页面的时候就会出现样式丢失。因为他会把一级路由放在请求路径进行请求。
eg:
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 Header from "./components/Header" import MyNavLink from ./components/MyNavLink export default class App extends Component { render() { return ( <div> <Header/> <div className="row"> <div className="col-xs-2 col-xs-offset-2"> <div className="list-group"> {/* 标签体中的内容会作为children属性传递给组件 */} <MyNavLink to="/yang/home">Home</MyNavLink> <MyNavLink to="/yang/about">About</MyNavLink> </div> </div> <div className="col-xs-6"> <div className="panel"> <div className="panel-body"> {/* 注册路由 */} <Switch> <Route path="/yang/about" component={About}/> <Route path="/yang/home" component={Home}/> </Switch> </div> </div> </div> </div> </div> ) } }浏览器:
解决·: 法一: index.html中引入样式的时候使用相对路径: <link rel="stylesheet" href="/css/bootstrap.css"> 法二: 使用 %PUBLIC_URL% ,%PUBLIC_URL% 代表的是public文件夹的绝对路径 <link rel="stylesheet" href="%PUBLIC_URL%/css/bootstrap.css"> 法三:使用HashRouter而不是BrowserRouter。
index.jsx // 引入react核心库 import React from react // 引入ReactDOM import ReactDOM from react-dom // 引入路由组件 import { HashRouter } from react-router-dom // 引入App组件 import App from ./App // 渲染App到页面 ReactDOM.render( <HashRouter> <App/> </HashRouter>, document.getElementById(root))路由的严格匹配与模糊匹配
模糊匹配一般情况下:NavLink的to 属性和Route的path属性匹配到的路径是一样的。
当 NavLink 的 to 属性是多级路由,但是Route的path只是匹配到第一级路由,那么组件会进行展示;
但是如果当 NavLink 的 to 属性是一级路由,但是Route的path匹配的是多级路由,组件是不会进行展示的。
这就是模糊匹配。eg:
import React, { Component } from react import { Route, Switch } from react-router-dom import About from ./pages/About import Home from ./pages/Home import Header from "./components/Header" import MyNavLink from ./components/MyNavLink export default class App extends Component { render() { return ( <div> <Header/> <div className="row"> <div className="col-xs-2 col-xs-offset-2"> <div className="list-group"> {/* 标签体中的内容会作为children属性传递给组件 */} <MyNavLink to="/home/a/b">Home</MyNavLink> <MyNavLink to="/about/c/d">About</MyNavLink> </div> </div> <div className="col-xs-6"> <div className="panel"> <div className="panel-body"> {/* 注册路由 */} <Switch> <Route path="/home" component={Home}/> <Route path="/about" component={About}/> </Switch> </div> </div> </div> </div> </div> ) } }组件正常显示:
但是如果是: import React, { Component } from react import { Route, Switch } from react-router-dom import About from ./pages/About import Home from ./pages/Home import Header from "./components/Header" import MyNavLink from ./components/MyNavLink export default class App extends Component { render() { return ( <div> <Header/> <div className="row"> <div className="col-xs-2 col-xs-offset-2"> <div className="list-group"> {/* 标签体中的内容会作为children属性传递给组件 */} <MyNavLink to="/home">Home</MyNavLink> <MyNavLink to="/about">About</MyNavLink> </div> </div> <div className="col-xs-6"> <div className="panel"> <div className="panel-body"> {/* 注册路由 */} <Switch> <Route path="/home/a/b" component={Home}/> <Route path="/about/c/d" component={About}/> </Switch> </div> </div> </div> </div> </div> ) } }组件就不展示了。
严格匹配就是NavLink的to 属性和Route的path属性匹配到的路径必须是一样的。
开启严格匹配的方式:给<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 Header from "./components/Header" import MyNavLink from ./components/MyNavLink export default class App extends Component { render() { return ( <div> <Header/> <div className="row"> <div className="col-xs-2 col-xs-offset-2"> <div className="list-group"> {/* 标签体中的内容会作为children属性传递给组件 */} <MyNavLink to="/home">Home</MyNavLink> <MyNavLink to="/about">About</MyNavLink> </div> </div> <div className="col-xs-6"> <div className="panel"> <div className="panel-body"> {/* 注册路由 */} <Switch> <Route exact={true} path="/home/a/b" component={Home}/> <Route exact={true} path="/about/c/d" component={About}/> </Switch> </div> </div> </div> </div> </div> ) } }严格匹配不要随便开启,可能会导致二级路由无法使用。
Redirect重定向的使用
当Route指明的所有路由都匹配不上的时候,就匹配Redirect中的路由。
使用:Redirect在所有Route标签之后使用,利用to属性指明路由地址。 <div className="col-xs-6"> <div className="panel"> <div className="panel-body"> {/* 注册路由 */} <Switch> <Route path="/home" component={Home}/> <Route path="/about" component={About}/> <Redirect to="/about"/> </Switch> </div> </div> </div>嵌套路由
嵌套路由就是在路由组件中再进行路由的导航和注册。
eg:效果:
新增和改动的页面:
Home/index.jsx import React, { Component } from react import {Switch, Route, Redirect} from react-router-dom import MyNavLink from ../../components/MyNavLink import News from ./News import Message from ./Message export default class Home extends Component { render() { return ( <div> <h3>我是Home组件</h3> <div> <ul class="nav nav-tabs"> <li> <MyNavLink to="/home/news">News</MyNavLink> </li> <li> <MyNavLink to="/home/message">Message</MyNavLink> </li> </ul> {/* 注册路由 */} <Switch> <Route path="/home/news" component={News}/> <Route path="/home/message" component={Message}/> <Redirect to="/home/news"/> </Switch> </div> </div> ) } }Home/News/index.jsx
import React, { Component } from react export default class News extends Component { render() { return ( <div> <ul> <li>news001</li> <li>news002</li> <li>news003</li> </ul> </div> ) } }Home/Message/index.jsx
import React, { Component } from react export default class Message extends Component { render() { return ( <div> <ul> <li> <a href="/message1">message001</a> </li> <li> <a href="/message2">message002</a> </li> <li> <a href="/message/3">message003</a> </li> </ul> </div> ) } }Home/index.js中的 <MyNavLink to="/home/news">News</MyNavLink>匹配的路由就是二级路由,注意这里的路由匹配规则不是直接匹配。所有的路由匹配会按照注册路由的顺序进行匹配, <MyNavLink to="/home/news">News</MyNavLink>会先匹配App.jsx中的注册路由,匹配到了<Route path="/home" component={Home}/>之后再去Home组件匹配注册路由,当匹配到了<Route path="/home/news" component={News}/>就在页面进行显示 。
Home/index.js中的<Redirect to="/home/news"/>, 就是设置当只匹配到了/home, 后面的路径未匹配时在Home页面默认显示的内容。
总结:
注册子路由是需要写上父路由的path值 路由的匹配是按照注册路由的顺序进行的路由传参
向路由组件传递params参数
使用方法 向路由组件传递params参数 (在路径后面直接接参数) <Link to={`/home/message/detail/001/消息1`}>{message.title}</Link> 注册路由时,接收路由组件传递的params参数 (在路径后面使用 :参数名 进行接收) <Route path="/home/message/detail/:id/:title" component={Detail}/>在路由组件中接收传递过来的的参数并使用
路由传递的参数存储在this.props.match.params 中: render() { const {id, title} = this.props.match.params } 例子Message/index.jsx
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:001, title:消息1}, {id:002, title:消息2}, {id:003, title:消息3} ] } render() { const {messageArr} = this.state return ( <div> <ul> { messageArr.map((message) => { return ( <li key={message.id}> {/* 向路由组件传递params参数 */} <Link to={`/home/message/detail/${message.id}/${message.title}`}>{message.title}</Link> </li> ) }) } </ul> <hr/> {/* 注册路由 */} {/* 接收路由组件传递的params参数 */} <Route path="/home/message/detail/:id/:title" component={Detail}/> </div> ) } }Detail/index.jsx
import React, { Component } from react export default class Detail extends Component { state = { dataDetail:[ {id: 001, context: 我是消息1的内容}, {id: 002, context: 我是消息2的内容}, {id: 003, context: 我是消息3的内容}, ] } render() { const {id, title} = this.props.match.params const {dataDetail} = this.state const findDetail = dataDetail.find((detailObj) => { return detailObj.id === id }) return ( <div> <div>ID: {id}</div> <div>TITLE: {title}</div> <div>Context:{findDetail.context}</div> </div> ) } }向路由组件传递search参数(query参数)
补充:qs库 qs库 可以使用stringify()方法将 对象格式转换为urlencoded编码格式 (key=value&key=value)
eg: import qs from qs let obj = {name:yang, age:20} // 转成 urlencoded格式 (key=value&key=value) console.log(qs.stringify(obj));输出:
name=yang&age=20 qs库 可以使用parse()方法将urlencoded编码格式 转换为对象格式 console.log(qs.parse(name=yang&age=20))输出:
{name: yang, age: 20} 使用方式 向路由组件传递search参数 (在路径后面直接接参数) <Link to={`/home/message/detail?id=${message.id}&title=${message.title}`}>{message.title}</Link> 注册路由时,无需接收search参数 <Route path="/home/message/detail" component={Detail}/>在路由组件中接收传递过来的的参数并使用
路由传递的参数存储在this.props.location.search 中:
但是还参数是未解析的状态,即urlencoded编码格式,需要借助qs库进行解析 render() { // 接收search参数 const {search} = this.props.location // slice(1)是为了去掉参数传递时的问号 const {id, title} = qs.parse(search.slice(1)) } 例子Message/index.jsx
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:001, title:消息1}, {id:002, title:消息2}, {id:003, title:消息3} ] } render() { const {messageArr} = this.state return ( <div> <ul> { messageArr.map((message) => { return ( <li key={message.id}> {/* 向路由组件传递params参数 */} {/* <Link to={`/home/message/detail/${message.id}/${message.title}`}>{message.title}</Link> */} {/* 向路由组件传递search参数 */} <Link to={`/home/message/detail/?id=${message.id}&title=${message.title}`}>{message.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/index.jsx
import React, { Component } from react import qs from qs let obj = {name:yang, age:20} // 转成 urlencoded格式 (key=value&key=value) console.log(qs.stringify(obj)); console.log(qs.parse(name=yang&age=20)) export default class Detail extends Component { state = { dataDetail:[ {id: 001, context: 我是消息1的内容}, {id: 002, context: 我是消息2的内容}, {id: 003, context: 我是消息3的内容}, ] } render() { // 接收params参数 // const {id, title} = this.props.match.params // 接收search参数 const {search} = this.props.location const {id, title} = qs.parse(search.slice(1)) const {dataDetail} = this.state const findDetail = dataDetail.find((detailObj) => { return detailObj.id === id }) return ( <div> <div>ID: {id}</div> <div>TITLE: {title}</div> <div>Context:{findDetail.context}</div> </div> ) } }向路由组件传递state参数
params参数和search参数都会显示在地址栏中,但是state参数就不会显示在地址栏上
使用方式 向路由组件传递state参数 (在路径后面直接接参数) <Link to={{pathname:/home/message/detail, state:{id:message.id, title:message.title }}}>{message.title}</Link> 注册路由时,无需接收state参数 <Route path="/home/message/detail" component={Detail}/>在路由组件中接收传递过来的的参数并使用
路由传递的参数存储在this.props.location.state 中,是对象格式 render() { const {id, title} = this.props.location.state } 例子Message/index.jsx
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:001, title:消息1}, {id:002, title:消息2}, {id:003, title:消息3} ] } render() { const {messageArr} = this.state return ( <div> <ul> { messageArr.map((message) => { return ( <li key={message.id}> {/* 向路由组件传递params参数 */} {/* <Link to={`/home/message/detail/${message.id}/${message.title}`}>{message.title}</Link> */} {/* 向路由组件传递search参数 */} {/* <Link to={`/home/message/detail?id=${message.id}&title=${message.title}`}>{message.title}</Link> */} {/* 向路由传递state参数 */} <Link to={{pathname:/home/message/detail, state:{id:message.id, title:message.title }}}>{message.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> ) } }Message/Detail/index.jsx
import React, { Component } from react import qs from qs let obj = {name:yang, age:20} // 转成 urlencoded格式 (key=value&key=value) console.log(qs.stringify(obj)); console.log(qs.parse(name=yang&age=20)) export default class Detail extends Component { state = { dataDetail:[ {id: 001, context: 我是消息1的内容}, {id: 002, context: 我是消息2的内容}, {id: 003, context: 我是消息3的内容}, ] } render() { // 接收params参数 // const {id, title} = this.props.match.params // 接收search参数 // const {search} = this.props.location // const {id, title} = qs.parse(search.slice(1)) // 接收state参数 const {id, title} = this.props.location.state || {} const {dataDetail} = this.state const findDetail = dataDetail.find((detailObj) => { return detailObj.id === id }) || {} return ( <div> <div>ID: {id}</div> <div>TITLE: {title}</div> <div>Context:{findDetail.context}</div> </div> ) } }浏览器地址中没有相关参数信息,但是页面刷新的时候参数不会丢失因为state参数存储在history的location的state中。
state参数是存储在路由组件的history的location的state中的,所以当浏览器的缓存被清空,history就被清空,参数就会丢失,再次访问该地址就无法获取参数就会报错。路由的两种模式push与replace
浏览器的history会存储我们访问的路径,存储结构是栈结构,存储模式有两种模式push模式和replace模式:
push模式:将新访问的路径直接压入栈 replace模式:用新访问的路径替换栈顶元素默认是push模式,可以通过给Link标签添加replace属性即可:
<Link replace={true} to={{pathname:/home/message/detail, state:{id:message.id, title:message.title }}}>{message.title}</Link>编程式路由导航
可以不通过Link标签来实现路由导航的路由是编程时路由导航,实际上是操作history身上的API。
注意:只有路由组件才有.props.history属性,才能直接使用如下变成式路由导航
this.props.history的API: replace(跳转路径): replace路由跳转 push(跳转路径):push路由跳转 go(n):前进或后退|n|步 goBack():后退1步 goForward():前进1步replace和push方法可以携带不同的参数(param、query、state)进行路由跳转。
replace跳转 // replace + params参数 this.props.history.