浅谈react-router@4.0 使用方法和源码分析
react-router-dom@4.3.0||react-router@4.4.1
react-router使用方法
配置router.js
importReact,{Component}from'react';
import{Switch,Route}from'react-router-dom';
constrouter=[{
path:'/',
exact:true,
component:importPath({
loader:()=>import(/*webpackChunkName:"home"*/"pages/home/index.js"),
}),
},]
constRouters=()=>(
{
router.map(({component,path,exact},index)=>{
return
})
}
);
exportdefaultRouters;
入口index.js
import{HashRouter}from'react-router-dom';
importReactfrom'react';
importReactDOMfrom'react-dom';
importRoutersfrom'./router';
ReactDOM.render(
,
document.getElementById('App')
);
home.js
import{withRouter}from"react-router-dom";
@withRouter
classHomeextendsReact.Component{
constructor(props:PropsType){
super(props);
this.state={};
}
goPath=()=>{
this.props.history.push('/home')
}
render(){
return(
home react-router源码解析
下面代码中会移除部分的类型检查和提醒代码,突出重点代码
第一步Switchreact-router
function_possibleConstructorReturn(self,call){
if(!self){
thrownewReferenceError("thishasn'tbeeninitialised-super()hasn'tbeencalled");
}
if(call&&(typeofcall==="object"||typeofcall==="function")){
returncall
}else{
returnself
}
}
varSwitch=function(_React$Component){
functionSwitch(){
//使用传递进来的组件覆盖本身
return_possibleConstructorReturn(this,_React$Component.apply(this,arguments));
}
Switch.prototype.render=functionrender(){
varroute=this.context.router.route;
varchildren=this.props.children;
varlocation=this.props.location||route.location;
varmatch=void0,child=void0;
//检查element是否是react组件,初始match为null,
React.Children.forEach(children,function(element){
//如果match符合,forEach不会进入该if
if(match==null&&React.isValidElement(element)){
var_element$props=element.props,
pathProp=_element$props.path,
exact=_element$props.exact,
strict=_element$props.strict,
sensitive=_element$props.sensitive,
from=_element$props.from;
varpath=pathProp||from;
child=element;
//检查当前配置是否符合,
match=matchPath(location.pathname,{path:path,exact:exact,strict:strict,sensitive:sensitive},route.match);
}
});
//如果有匹配元素,则返回克隆child
returnmatch?React.cloneElement(child,{location:location,computedMatch:match}):null;
};
returnSwitch;
}(React.Component);
总结:switch根据location.pathname,path,exact,strict,sensitive获取元素并返回element
第二步Routereact-router
varRoute=function(_React$Component){
functionRoute(){
var_temp,_this,_ret;
//获取参数
for(var_len=arguments.length,args=Array(_len),_key=0;_key<_len;_key++){
args[_key]=arguments[_key];
}
//修改this
return_ret=(
_temp=(_this=_possibleConstructorReturn(this,_React$Component.call.apply(_React$Component,[this].concat(args))),_this),
//检查当前元素是否符合match
_this.state={match:_this.computeMatch(_this.props,_this.context.router)},_temp),
//这里是真正return
_possibleConstructorReturn(_this,_ret);
}
//设置content
Route.prototype.getChildContext=functiongetChildContext(){
return{
router:_extends({},this.context.router,{
route:{
location:this.props.location||this.context.router.route.location,
match:this.state.match
}
})
};
};
//根据参数检查当前元素是否符合匹配规则
Route.prototype.computeMatch=functioncomputeMatch(_ref,router){
varcomputedMatch=_ref.computedMatch,
location=_ref.location,
path=_ref.path,
strict=_ref.strict,
exact=_ref.exact,
sensitive=_ref.sensitive;
if(computedMatch)returncomputedMatch;
varroute=router.route;
varpathname=(location||route.location).pathname;
returnmatchPath(pathname,{path:path,strict:strict,exact:exact,sensitive:sensitive},route.match);
};
//设置match
Route.prototype.componentWillReceiveProps=functioncomponentWillReceiveProps(nextProps,nextContext){
this.setState({
match:this.computeMatch(nextProps,nextContext.router)
});
};
Route.prototype.render=functionrender(){
varmatch=this.state.match;
var_props=this.props,
children=_props.children,
component=_props.component,
render=_props.render;
var_context$router=this.context.router,
history=_context$router.history,
route=_context$router.route,
staticContext=_context$router.staticContext;
varlocation=this.props.location||route.location;
varprops={match:match,location:location,history:history,staticContext:staticContext};
//检查route是否有component组
if(component)returnmatch?React.createElement(component,props):null;
//检查是否包含render组件
if(render)returnmatch?render(props):null;
//withRouter使用的方式
if(typeofchildren==="function")returnchildren(props);
if(children&&!isEmptyChildren(children))returnReact.Children.only(children);
returnnull;
};
returnRoute;
}(React.Component);
总结:route渲染的方式:componentrenderchildren,代码示例用的是component,route是检查当前组件是否符合路由匹配规则并执行创建过程
第三步HashRouterreact-router-dom
importRouterfrom'./Router'
import{createHistory}from'history'
varHashRouter=function(_React$Component){
functionHashRouter(){
var_temp,_this,_ret;
//参数转换为数组
for(var_len=arguments.length,args=Array(_len),_key=0;_key<_len;_key++){
args[_key]=arguments[_key];
}
return_ret=(
_temp=(_this=_possibleConstructorReturn(this,_React$Component.call.apply(_React$Component,[this].concat(args))),_this),
_this.history=createHistory(_this.props),_temp),//创建history
_possibleConstructorReturn(_this,_ret);//真正返回的东西返回this
}
HashRouter.prototype.render=functionrender(){
//返回一个Router,并且把history,children传递给Router
returnReact.createElement(Router,{history:this.history,children:this.props.children});
};
returnHashRouter;
}(React.Component);
总结通过history库里面createHistory创建路由系统
第四部Routerreact-router
varRouter=function(_React$Component){
functionRouter(){
var_temp,_this,_ret;
//获取参数,和其他组件一样
for(var_len=arguments.length,args=Array(_len),_key=0;_key<_len;_key++){
args[_key]=arguments[_key];
}
return_ret=(_temp=(_this=_possibleConstructorReturn(this,_React$Component.call.apply(_React$Component,[this].concat(args))),_this),_this.state={
match:_this.computeMatch(_this.props.history.location.pathname)//返回路由对象
},_temp),_possibleConstructorReturn(_this,_ret);//返回this
}
//返回context
Router.prototype.getChildContext=functiongetChildContext(){
return{
router:_extends({},this.context.router,{
history:this.props.history,
route:{
location:this.props.history.location,
match:this.state.match
}
})
};
};
Router.prototype.computeMatch=functioncomputeMatch(pathname){
return{
path:"/",
url:"/",
params:{},
isExact:pathname==="/"
};
};
Router.prototype.componentWillMount=functioncomponentWillMount(){
var_this2=this;
var_props=this.props,
children=_props.children,
history=_props.history;
//启动监听当hash改变是做一次检查,并返回unlisten取消事件
this.unlisten=history.listen(function(){
_this2.setState({
match:_this2.computeMatch(history.location.pathname)
});
});
};
//销毁前取消监听
Router.prototype.componentWillUnmount=functioncomponentWillUnmount(){
this.unlisten();
};
//children是HashRouter传递进来的
Router.prototype.render=functionrender(){
varchildren=this.props.children;
returnchildren?React.Children.only(children):null;
};
returnRouter;
}(React.Component);
总结history是一个JavaScript库,可让您在JavaScript运行的任何地方轻松管理会话历史记录。history抽象出各种环境中的差异,并提供最小的API,使您可以管理历史堆栈,导航,确认导航以及在会话之间保持状态。
第五部withRouter
varwithRouter=functionwithRouter(Component){
varC=functionC(props){
//获取props
varwrappedComponentRef=props.wrappedComponentRef,
remainingProps=_objectWithoutProperties(props,["wrappedComponentRef"]);
//Route组件children方式
returnReact.createElement(Route,{
children:functionchildren(routeComponentProps){
//这里使用的是route组件children(props)
//routeComponentProps实际等于{match:match,location:location,history:history,staticContext:staticContext};
returnReact.createElement(Component,_extends({},remainingProps,routeComponentProps,{
ref:wrappedComponentRef
}));
}
});
};
C.displayName="withRouter("+(Component.displayName||Component.name)+")";
C.WrappedComponent=Component;
//该类似于object.assign(C,Component),得到的结果是C
returnhoistStatics(C,Component);
};
到这里真个流程基本结束了,这只是react-router的一种使用方式的解析,本文的目的是理解react-router的运行机制,如果有什么错误还望指出,谢谢
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。