React-Rouer精水(一)

       看了网上这么多的react-router源码解析,也只是大概告诉大家每个函数到底干嘛的,于是小编想精水一篇,因为作者没有搭建相关的编译环境,导致调试困难,小编自己不想搭建编译环境,原因就是嫌弃麻烦,所以主要用肉眼看,用大脑思考,知难行易,慢慢的小编看的差不多了,今天的文章可能只能水几个组件,以后如果有时间,小编会继续水!

      首先,我们来看Rouer这个组件,也是第二核心的组件,源码大家可以去github上找到,下面小编来为大家一点点拆解。说白了万变不离其宗,很多都是js,不管如何变化,es6也好,es7也罢,很多都是js写的语法糖,只是大家都接受了,习惯了这种写法,但是本质还是js。

      Rouer这里开头有个 import RouterContext from "./RouterContext";,于是我们不得不打开RouterContext这个文件,看看RouterContext是干啥的。

      这是RouterContext的相关代码:
      

     这里主要用到了create-react-context这个react的属性,为了方便组件之间传递属性。createNamedContext这个方法返回一个封装好的传递属性的组件,到这里,我们可以很清晰的发现,RouterContext这个组件就是把create-react-context封装了下,方便传值。下面我们回到Rouer这个组件,因为代码比较长,我们截图截取2次。
    
      

      首先看第11行那个函数,static computeRootMatch,这个方法是Router组件的静态方法,用来返回一个对象,同时按照传入的pathname是不是'/',来动态获取isExact的值,通过文档,我们发现它的作用是当为true时候,整个文档需要匹配,具体我们可以找到第60行,我们发现是作为参数传递下去的。我们可以根据参数this.state.location.pathname,找到18到20行,props.history.loaction,我们可以知道props会传入location,大家可能想知道这个history哪里来的,其实这个是从hashhistory,browerhistory等传入的,这里不展开。接下来就是重点了:大家可以看到有个props.history属性和history方法,这里小编告诉大家,这个是history的npm包,对浏览器的自身携带的location.history做了封装,有兴趣的大家可以自己去看看history包。大家再来看第30到38行,重点来了,第31行props.history.listen(),这个是history包的一个监听url改变的方法,按照不同的location,进行setState渲染,从而刷新整个页面路由,这也就是为何组件显示都要和路由绑定的原因。接下来大家看第41行到47行,这个是防bug的,本质就是第一次加载Router把当前页路由存进state,现在我们需要看第53行到64,是不是看到了我们熟悉的render,返回一个被RouterContext.Provider包裹的组件,方便下面的组件取值。大家还记得一开始提到的isExact吧,这里展开下,大家可以看Switch.js这个文件,下面是组件的代码:
      

      大家看第15行可以看到RouterContext.Consumer,这就接受了上面父组件传入的value,我们重点找到match,准确的说是context.match,我们来看第27行,我们可以看到遍历每一个子元素,目的是用来匹配某个符合要求的路径。大家具体来看第31行,相信聪明的你已经知道这里的child是Route这个路由组件吧,我们可以获得定义给每个路由的path,然后关键的地方来了,大家看第33行,如果path存在,就match复制为matchPath(location.pathname, { ...child.props, path })这个方法发返回值,我们来看Switch.js第7行,import matchPath from "./matchPath",找到对应的代码:

      

      这个方法我们看具体的42行,const match = regexp.exec(pathname),因为我们传入的pathname是固定的,准确的是某个路由对应的location.pathname的值是唯一的,所以按照path-to-regexp这个npm包提供的api匹配到的路由也是唯一的,至于如何匹配的,大家可以去看下相关api,具体这里不作展开。接下来我们来看第44行,如果我们上面没有匹配到,我们这里就返回null,如果匹配到了,就新返回一个match对象,大家看第51到60行,我们继续看第47行,大家又看到了熟悉的isExact,大家可以看到,const isExact = pathname === url;到这里我们清楚了,这个isExact其实就是一个标志,具体作用是让使用者来判断当前页面的的路由的地址是不是和子元素的Route组件的path匹配,如果匹配到了才能返回一个match对象,如果匹配不到返回的也是空!这段代码总结,是匹配了2次,第一次,路由地址匹配的match是不是存在,如果match存在,说明正则校验通过,就进行url匹配,这个url按照Route组件的path拼接出来的,具体可以看第31行const { path, exact = false, strict = false, sensitive = false } = options,至于这个options大家可以看Switch.js的第34行和31行,可以发现就是子组件Route的path,在matchPath的最后,作者为了方便扩展,又把isExact返回了。
      现在,我们再来看Switch.js第33行到第35行,我们可以看到,当Route存在path的情况下,如果匹配不到对应的match,就返回祖先组件提供的match,即Router.js第60行和第12行,也就是匹配到/这个根路径,至此这篇文章分析完毕!

      大家有时间可以看看Route组件,小编有时间会把最重要的Route组件水一遍,大家可以按照我这个方法去看看!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值