很久没有碰前端,最近重新学习react-router,发现版本升级到了4.2.0,使用方法都做出了相应的调整。
Redirect组件
开发中遇到的需求,ajax请求返回状态如果成功则跳转成功页面(很常见吧)。由于是单页应用,跳转前后用Route组件渲染,跳转用Redirect进行控制。测试demo结构如下:
其中index.html,server.js和wepack.config.dev.js是我在写webpack热更新所用来编译项目的文件,大家可以用自己方式。
index.js
import React,{Component} from 'react'
import {render} from 'react-dom'
import { BrowserRouter as Router, Route ,Redirect,Switch} from "react-router-dom";
const AppMain = document.getElementById("main");
class Page_01 extends Component{
constructor(props){
super(props);
this.state={
redirect:false
}
this.redirectHanlder = this.redirectHanlder.bind(this);
}
redirectHanlder(){
this.setState({
redirect:true
});
}
render(){
let {redirect} = this.state;
return (
redirect
?
<Redirect
to={
{
pathname:"/p2", (1)
search:"p1=1&p2=2", (2)
state:{"name":"kiramario","age":26} (3)
}
}
/>
:
<div>
<h2>Page_01</h2>
<button onClick={this.redirectHanlder}>jump to page 2</button>
</div>
);
}
}
class Page_02 extends Component{
constructor(props){
super(props);
console.log(this.props)
}
render(){
return (
<div>
<h2>Page_02</h2>
</div>
);
}
}
render(
<Router>
<Switch> (4)
<Route exact path="/" component={Page_01}/>
<Route path="/p2" component={Page_02}/>
<Redirect exact strict from="/dd/" to="/p2" /> (5)
</Switch>
</Router>,
AppMain
);
1、 渲染页面时,Router根据Route中path的值,按顺序去匹配当前浏览器的location.pathname并加载。此例中在浏览器地址中输入http://127.0.0.1:9090 渲染Page_01,输入http://127.0.0.1:9090/p2渲染Page_02。
2、Switch组件,如上代码中(4)部分,表示Router按顺序去匹配当前url。 匹配到第一个就不在往下继续寻找。
Redirect本质上是一个组件,因此需要放在rende函数中,index中的逻辑如下:
- 在浏览器中输入http://127.0.0.1:9090,此时会渲染出Page_01
- 在Page_01模块中点击jump to page 2按钮,调用setState方法,将this.state.redirect设置为true,组件重新渲染,返回Redirect组件。
- 浏览器地址栏跳转到http://127.0.0.1:9090/p2,渲染Page_02模块。在Page_02的构造函数中
console.log(this.props)
,结构如下图:
router实现路由切换的原理是用到了H5 API中的history,我们看到this.props.history有push和replace方法实际上是原生接口history.replaceState和history.pushState的封装(写这段话的时候比较虚,主要是因为我是通过测试代码来验证,并没有去找源代码)
to
参数表示渲染Redirect组件后跳转的url地址,有两种表达方式,string或者 json对象,string形式后面跟要跳转的url字符串。json对象里面有3个参数。
- pathname,跳转到的URL。
- search,跳转后的url参数。此例中,跳转后的url是http://127.0.0.1:9090/p2?p1=1&p2=2
- state,会保存在this.history.location.state中,可以借此保存数据
push
通过this.props的截图可以看到,this.props.history中的action为REPLACE,表示在默认情况下,它调用的是history.replaceState方法,当前浏览历史被修改,因此浏览器返回键无效。
加上push参数会调用history.pushState, <Redirect push to={{...} />
此时浏览器将url加入到浏览历史中,浏览器后退键有效,在此例中后退会回到http://127.0.0.1:9090,Page_01模块。
打开Redirect.js源码,找到这一段。可以看到,如果有push,调用hisotry.push (history.pushState的封装)
Redirect.prototype.perform = function perform() {
var history = this.context.router.history;
var _props = this.props,
push = _props.push,
to = _props.to;
if (push) {
history.push(to);
} else {
history.replace(to);
}
};
from,exact,strict
这三个参数只能用在Switch组件下面的Redirect组件中,如上代码所示。
<Redirect exact strict from="/dd/" to="/p2" />
from
:表示浏览器地址中的匹配跳转的pathname,如果当前from匹配到当前浏览器pathname,触发此Redirect。浏览器输入http://127.0.0.1:9090/dd/时会立马跳转到http://127.0.0.1:9090/p2
exact
:规定from匹配pathname时是精确还是模糊。
- 精确:from=”/dd” 必须匹配 http://127.0.0.1:9090/dd
- 模糊:from=”/dd“ 可以匹配http://127.0.0.1:9090/dd/ff/ee
strict
:表示是否匹配pathname部分末尾的“/”符号,如果有此参数,Redirect组件的from和浏览器pathname匹配时要考虑末尾的”/”。例如(5)所示,from=”/dd/” 必须匹配 http://127.0.0.1:9090/dd/而非 http://127.0.0.1:9090/dd