浅谈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=()=>(); exportdefaultRouters; { router.map(({component,path,exact},index)=>{ return }) }
入口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的运行机制,如果有什么错误还望指出,谢谢
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。