读react-router源码有感

485 阅读3分钟

最近拜读了react-router源码(对应文档,版本为v3.2.1),记录一下源码中个人认为非常棒的细节。

1. 入口文件

index.js
从入口文件可以看出,react-router将自己分为四大类:

  • components:功能性组件,会进行渲染;
  • components(configuration):配置性组件,配合Router组件使用,生成路由表
  • utils:工具函数,配合路由组件解析
  • histories:history模块的封装

从上面可以看出,react-router将功能划分非常明确,文件划分值得学习。

2. 功能入口

Router组件为react-router的功能入口,在componentWillMount>createTransitionManager中可以发现:react-router利用transitionManagerhistory模块进行了封装。

这么做有个大好处:Router本身不依赖当前环境,只对history模块的location变化做监听,将得到的location进行解析,进行后续的匹配。如此设计,Router只需对location这一个对象进行分析,不再关心地址何时变化,如何对变化进行监听。甚至,你可以自行传入一个自定义对象(history),在内存中模拟"地址"变化,将"地址"变化维护在栈中,实现"地址"切换的功能。

其实,react-router整体就两大块:Routerhistoryhistory告诉Router当前地址是多少,Router告诉React需要渲染哪些组件。

3. 细节记录

3.1 AsyncUtils

此文件中有两个函数:loopAsync,mapAsync。均为批量执行一系列任务,这些任务中可能存在异步任务。设计这种功能函数有两个关键点:

1.error first:错误优先。即执行回调函数时,第一个参数一定是错误信息;

2.end immediately:立即结束。允许调用者在某个任务中直接结束,进入所有任务结束回调。

3.2 Link

Link

  1. displayName:组件在调试时的名字。包含:react报错时提示的组件名,以及react-devtools调试面板展示的组件名。
  2. propTypes:组件接收属性的类型验证(可自定义类型)。当类型不对时,react会抛出警告。添加此属性后,IDE也会有智能提示。算是为弱类型的js提供一个健壮性方案。

3.3 isActive

deepEqual在比较数组内元素是否相同时,提前判断两个数组的长度,在数组长度不相同时,会提前停止判断,提高比较速度。

3.4 PatternUtils

compilePattern
compilePattern函数。解析一段规则会很耗时,使用CompiledPatternsCache将解析结果做了缓存,典型的用空间去换取时间。这里也提现了纯函数的好处:

相同输入永远得到同样的输出

也正因为如此,才能将耗性能的解析过程做缓存。

_compilePattern函数,真正的解析函数。

  • 对正则表达式matcher的使用
  • 通过路由配置,生成正则regexpSource,降低开发者对正则的使用难度

上面对输入字符进行扫描,生成tokens的过程,让我想起了代码转换过程:从一个形态转换为另一个形态。

github上有一个开源项目the-super-tiny-compiler,用极简的解释了如何写一个代码编译器。只要步骤分为:

1.Parsing将原始代码转换为抽象的表示。

2.Transformation操作这种抽象的表示,做编译、转换目的。

3.Code Generation代码生成,根据新的抽象表示,转换为新的代码。

简述上述过程,即:【code】>【AST】>【code】。

以上是babel对代码降级的核心思路,也是从一种语言转换为另一种语言的核心思路。

【End】