React-router从0到1

Tags: JavaScript, React

引子

本文会讨论react生态下的常用路由库,React-router的版本迭代与源码架构,并尝试探讨路由思维的变化与未来。

什么是路由?

路由是一种向用户显示不同页面的能力。 这意味着用户可以通过输入URL或单击页面元素在WEB应用的不同部分之间切换。

版本

为了探究react-router设计思维,从v3开始有这几个版本:

  • react-router 3「静态路由」

  • react-router 4「动态路由」

  • react-router 5「意外发布」

  • @reach/router「简化轻量」

  • react-router 6「完全方案」

让我们逐个参与讨论。

react-router3:静态路由

静态路由的设计如下图所示:

React.render((
  <Router>
    <Route path="/" component={Wrap}>
      <Route path="a" component={App} />
      <Route path="b" component={Button} />
    </Route>
  </Router>
), document.body)

特点:

  • 路由集中在外层

  • 页面路由配置通过Route组件的嵌套而来

  • 布局和页面组件是完全纯粹的,它们是路由的一部分

v3静态路由的设计对前端工程师来说,相对更易接受,因为前端工程师很多都接触过类似的路由配置设计,比如express、rails等框架。

虽然细节各有不同,但是思路大致相同——将path静态映射为渲染模块。

react-router4:动态路由

虽然v3以一种质朴无华的方式完成了基本的路由工作,但react-router的几个核心成员感觉现有的实现严重受ReactAPI的制约,并且实现方式也不够优雅。

于是,经过了激烈的思考与讨论,他们大胆地在v4中做出了比较激进的更迭。

React-router4不再提倡静态路由的集中化架构,取之的是路由存在于布局和 UI 之间:

const App = () => (
    <BrowserRouter>
      <div>
      <Route path="/a" component={A}/>
      </div>
    </BrowserRouter>
);

const A  = ({ match }) => (
    <div>
     <span>A</span>
      <Route
     path={match.url + '/b'}
     component={B}
      />
    </div>
);

const B = () => <div>B</div>;

我们来看以上代码的逻辑

  1. 一开始在App组件里,只有一个路由/a

  2. 用户跳转访问/a时,渲染A组件,浏览器上出现字母A,然后子路由/b被定义

  3. 用户跳转访问/a/b时,渲染B组件,浏览器上出现字母B

我们可以看到,在v4中:

  • 路由不再集中在一处

  • 布局和页面的层叠不再由层叠的<Route>组件控制,<Route>与组件为替换的关系

  • 布局和页面组件也不在是路由的一部分

这被称之为「动态路由」。

动态路由

传统静态路是在程序渲染前就定义好。

而动态意味着路由功能在应用渲染时才动态生成,这需要把路由看成普通的 React 组件,传递 props 来正常使用,借助它来控制组件的展现。这样,没有了静态配置的路由规则,取而代之的是程序在运行渲染过程中动态控制的展现。

动态路由将带来很大的好处。比如代码分割,也就是react常说的code splitting,由于不需要在渲染前决定结果,动态路由可以满足代码块的按需加载,这对于大型在线应用非常有帮助。

但是,毕竟路由对一个应用的架构来说非常重要,这么大的改变显得过于激进,这会改变以前开发者比较习惯的一些模式,由于这次的更新过于激进,遭到了开发者们的一些负面反馈:

4aca1320961fb72c6e82fa13dfd13994.png

这就要讨论到动态路由的缺点了:

  • 不够直观,你无法从顶层知道程序中所有的路由,应用一层一层下来,搞不清最后显示出来什么,可读性很差

  • 测试困难。组件中掺杂了路由逻辑,原本对针对组件的单元测试(功能层面)完全不需要知道路由的存在,而现在就要考虑了

b0a828744717f3aea37b6f3812cd2b39.png

由于React-router团队保证v3会持续维护,所以当时很多开发者没有选择升级。

react-router5:沿用

原本只是计划发布 React Router 4.4 版本,但由于不小心误用了^字符,将依赖错误地写成 "react-router": "^4.3.1",导致报错。于是最后团队决定撤销 4.4 版本,直接改为发布 React Router v5。

react-router5延续了动态路由的模式,但是提供了更加直观的写法:

export default function App() {
  return (
    <Router>
      <Switch>
        <Route path="/about">
          <About />
        </Route>
        <Route path="/topics">
          <Topics />
        </Route>
        <Route path="/">
          <Home />
        </Route>
      </Switch>
    </Router>
  );
}

以上的写法,/about显示<About>组件,/topics显示<Topic>组件,根路由显示<Home>组件。

同时,v5还允许你将路由配置作为一个config的json数据,写在组件外引入。

<Route>将作为父组件用于匹配路由,同时还有一系列辅助组件,比如<Switch>可以限制子元素进行单一的路由匹配。当然,这也会带来一定的

@reach/router:简洁

Reach-Router 是 ReactRouter 成员 Ryan Florence 开发的一套基于 react 的路由控件。

81200367131b5406be33f92a40155f5d.png

那么已经有比较成熟的 ReactRouter 了, 为什么要”再”做一套 Router 呢?

  • Accessibility「易用」

  • 相对链接的跳转方式

  • 嵌套的路由配置

  • 合适的路径优先(顺序不会造成影响)等等

优点:小而简

  • 4kb,压缩后比react-router小40kb左右,同时有更少的配置

  • 比起react-router需要3个包(historyreact-router-domreact-router-redux),reach-router只需要一个

  • 不需要在store配置router相关信息

  • 不需要显示的使用history

  • 基本一样的api,学习成本非常低

  • 源码非常简洁,总共就3个文件,900行

react-router6:终极方案

2021年11月,react-router 6.0.0 正式版发布:

  • 全部用 ts 重写

  • 不以 '/' 开头,都是「相对路径」

  • 路由按照最佳匹配选择,可以嵌套或者分散

v6的设计可以说很大程度参照了@reach/router,API和@reach/router v1.3非常相似。因此,官方也宣称v6可以被看做@reach/router的v2。

总体来说,v6更像是一个以前版本的完善和整合,相对路径与嵌套分散的选择方式,让大家能够按个人喜好去构建路由。

源码

探讨完设计哲学与版本更迭,我们正式进入从0到1的源码学习。

本文对源码的探讨,就是以v6为基础(中间存在各种简

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值