前天学习了Link
组件源码, 今天再来看一下与之相似的NavLink
一、更新
[2019-4-21]
Changed
- 改进文章排版👌
二、前言
经过上一篇文章Link的战火洗礼, 可以了解到, Link
作为沟通react-router
和react
之间的桥梁, 经历click -> url变化 -> history(onListen) -> Switch -> Route render
的过程, 据此, 有关Link
的面试题便可迎刃而解.
正式开始分析之前, 先来回想一下我们平时是如何使用NavLink
的?
PS: 传入对应的
activeStyle
或者activeClass
, 点击之后, 如果对应的组件成功渲染, 则该NavLink
的样式也会改变.
带着平时使用的思路去分析源码, 会又事半功倍的效果.
OK, 正式开始对NavLink
的探索.
三、细说
先来看一下NavLink
的大致结构, 可以看到, 其实NavLink
是一个functional
组件, functional
相较于classes
的优势很多:
- 高度可拓展
- 易于优化重构
- 渲染性能较优
在react v16.7
之后的hooks
加持之下, 可用性更是飞步提升.
接着来看一下NavLink
接收了哪些props
?
1 | function NavLink({ |
对应的props的功能如下表所示:
aria-current | 残障人士专用, 可参考这里 |
activeClassName | 匹配时添加的类名 |
activeStyle | 匹配时添加的样式 |
className | NavLink的类名, 会附加到Link |
exact | 是否实行完全匹配 |
strict | 是否实行严格匹配 |
isActive | 自行计算高亮条件 |
location | 与当前to 进行比较的location, 默认是context.location |
style | 默认样式 |
to | 跳转的url |
…rest | 额外参数 |
接着, 可以看到下面:
1 | const path = typeof to === "object" ? to.pathname : to; |
值得注意的是, 这里的excapedPath
很奇怪, 一直想不通为什么要进行这个操作? 怀着好奇的心理点开注释的链接, 可以看到:
该函数会将字符串中的特殊字符进行转义处理, 那么这到底有咩用? 假设有一个特殊的path
序列是这样的:
1 | const path: string = '/user\duan/profile/se+cr*et'; |
用户想传递该path
, 该path
中含有特殊字符, 那么escaped
会将转义字符再此进行转义, 便于传递.
接着往下看:
1 | return ( |
通过一个Route
组件包裹, 根据其的match
判断是否active
, 然后在Route
中返回对应的Link
组件, 将处理后的rest
等参数传递给Link
组件.
这一步, 我刚开始看了好几遍都没看懂, 很难理解, 难点在于为什么要用一个Route
??? 它的本质是为了获取match
, 根据match
匹配成功与否, 进行动态添加样式, 理解了这点, 就没啥可说的了.
另外, 还有一种思路 —— 通过获取Link
的innerRef
, 然后通过matchPath
自行比对location.pathname === to
, 根据判断的结果, 直接操作DOM
, 这么做也是可以的, 不过值得思考的是, 这不正好违背了Route
组件的设计原则:
PS: 匹配路径规则, 渲染组件
既然有更专业的Route
来帮我们作这件事, 何乐而不为呢? 为什么还要再次比对呢? 得不偿失.
🆗, NavLink
的源码思路解析大致已经完成, 接下来继续完善自己的yyg-react-router-dom
库.
四、实践
老样子, 首先定义我们所需的一切props
, 具体的props
可以看这里.
1 | // src/yyg-react-router-dom/components/NavLink.tsx |
接着, 到了下面, 根据判断match
是否为null来断定path是否匹配:
1 | return ( |
注意! 上面有一个值得注意的点, 那就是Route
的children
和render
是不同的, 两者的具体差别可以看这里, 所以, 这里只能使用children
来渲染.
五、测试
完成了自己的yyg-react-router-dom
库, 可以来做一个简单的测试.
PS: 当然, 测试用例是随意的
打开App.tsx
, 修改render
中的测试逻辑如下:
1 | //src/App.tsx |
然后, 在vscode
的指引下, 进入One.tsx
组件, 同样修改render
中的逻辑:
1 | return ( |
可以看到, 总共有三个锚点
, 第一个为Link
, 为了与NavLink
的效果加以区分, 然后在最下方放置需要router-view
, 也就是需要渲染的组件. 大致结构与在项目中使用的差不多的…
接着, 在浏览器中可以看到效果:
点击Home
按钮, 视图变了, 但是链接颜色没变化? 当然了, 因为这只是普通的Link
组件, 你想它有啥效果? 接着看下面两个, prefect, 两个锚点样式随着url变化而改变.
此时, 对于NavLink
的测试工作已经完美结束了
六、源码
源码已上传, 点这里
七、总结
PS: 路漫漫其修远兮, 吾必反复求其知
最后, 一张思维脑图来结束今天的源码学习