【青训营】- React Router 路由层√

533 阅读6分钟

📄目录结构

  • 服务端路由
  • 客户端路由
  • MPA和SPA
  • React Router是什么
  • Router组件
    • BrowserRouter
    • HashRouter
    • Route
    • Switch
    • 路由跳转
    • 路由Hook
  • 集成React Router

🔖Demo

标题Demo
Router常用组件BrowserRouterHashRouterDemo
集成React RouterDemo

像函数组件和类组件那样,路由也有两个分类。一个是服务端路由,另一个是客户端路由

服务端路由

请求发送到服务端,服务端返回对应的页面内容,以字节跳动的官网为例:www.bytedance.com

image.png

image.png

它的请求返回结果是一个完整的HTML文档,这其实就是一个服务端路由的例子。我们在浏览器发送一个请求,然后服务器接收到这个请求并返回对应的页面的内容。

客户端路由

请求不发送到服务器,由客户端代码更新页面内容,以掘金的官网为例:juejin.cn/

image.png 我们看到最开始进入页面,依然发送的是服务端的请求,然后返回完整的页面。

但是我们点击“资讯”,它并没有新的请求发送到服务端

image.png

但是我们点击字节官网的“我们的产品”时,就会发送新的请求/products到服务器端。

image.png

在浏览器里我们观察发现

image.png

如果这个小图标变成X再变成圆,表示这个请求是从服务端处理过,然后返回一个完整的页面过程。

image.png

如果是客户端路由,这个图标它并不会去显示刷新。

由此我们引入MPA(多页面应用)和SPA(单页面应用)的概念。

MPA和SPA

image.png

左图是服务端路由的场景,MPA-多页面应用(Multi Page Application)。我们请求一个应用地址,比如说应用的根路径/,服务端会返回这个HTML页面。然后当我们去跳转另外一个路径,比如说home路径/home,也会经过服务端处理,服务端又会返回另外一个页面。

这就是传统的多页面应用方式,每一个页面都会对应一个HTML,每个路由发生变化的时候都会经过服务端的处理,然后服务端返回对应的HTML页面。

客户端路由的话,我们首次去请求应用的根路径/,服务端也是会处理然后返回一个HTML,在之后我们跳转到其它路径的时候,并不会发送到服务端,而是它自己就处理掉。那整个过程中,只会有一个HTML,那这就是所说的SPA-单页面应用(Single Page Application)。

之后你还可能遇到SSR(Server-Side Rendering)和CSR(Client-Side Rendering),需要注意区分。

React Router是什么

在我们日常开发中,SPA是最常用的一种前端应用的组织方式。

React Router其实就提供了SPA下,我们客户端路由应该怎么去管理的几个方案。

Router组件

常用的如下:

  • BrowserRouter:根据URL中的path做路由跳转
  • HashRouter:根据URL中的hash部分做路由跳转
BrowserRouter

当我们点击导航栏的时候,path这部分会发生变化。

image.png

完整代码请查看Demo

HashRouter

如果是HashRouter呢,这时候我们点击的时候,变化的是URL#号后面的部分,#后面的部分其实就是URL的hash部分

image.png 这时候路由是根据Hash部分的变化,然后去渲染相关页面的内容的。

这其实就是BrowserRouterHashRouter的区别。

在日常使用当中,我们一般会去使用BrowserRouter,而HashRouter存在更多是为了兼容一些老版本的浏览器,因为BrowserRouter它内部的实现应用了History.push这些API。老版本的浏览器可能不支持这些。所以React提供了一个HashRouter作为一个降级方案。

Route

当url和Route中定义的path匹配时,渲染对应的组件,重要props:path、exact。

image.png

如果在home页不加exact的话,那么不管点击哪个,url是对应的标签,内容都是home的内容,也就是都会被home匹配。

image.png

要避免这个问题我们就用exact。添加exact属性后,只有严格相等,里面的组件才会被渲染。

Switch

就是上面示例中和Route组合使用的Switch。 当找到Switch组件内的第一个路由规则匹配的Route组件后,立即停止后续的查找。

路由跳转

声明式的组件方式:Link

命令式的API调用方式:history.push

image.png

它的底层会渲染出a标签。

image.png

路由Hooks

我们再来看一下如何通过命令式的API来做路由跳转。

  • useHistory:获取history对象
  • useParams:获取路由中的参数

首先,在Switch里定义一个新的Route

    <Route path="/user/:username">
        <User />
    </Route>

接着,在Home组件中使用useHistory

    function Home() {
        const history = useHistory();
        return (
          <div>
              <h2>Home</h2>
              <button onClick={() => {
                  history.push("/user/jason");
              }}>
                  Go User{" "}
              </button>
          </div>
        );
    }

我们通过history.push("/user/jason")这样一个路径,这个jason是会作为username这个参数的值传入到Switch里的Route path="/user/:username"里的User这个组件内。

User组件中使用useParams

    function User() {
        const params = useParams();
        const username = params.username;
        return <div>Welcome: {username}</div>;
    }

User这个组件内,我们通过useParams这个API获取到路由路径当中的参数,再通过params.username获取到传入的这个参数的值,然后将参数值在这里渲染出来。

这个其实就是useParms这个API的作用。

集成React Router

在实战案例中,集成ReactRouter

主讲人在github上demo

在这篇文章中,我们主要关注实战里的目录结构

image.png 目录里的features表明的是功能模块,这个功能模块可以是一个页面级的(一个路由页面代表一个模块),也可以是一个复杂的前端页面,页面当中的某一个模块。比如说,一个通知模块。总之,一个features里放的是不同页面拆分出来的小features。

每个小features下它会去包含开发这个features所需要的所有的业务逻辑或代码。如果各个features之间有一些通用的代码需要复用的话我们该怎么办呢,会把它往上去提,提到和features这个文件夹同级的文件中。

比如说各个组件当中都会去用到一个Navbar顶部的导航栏这样的组件。我们把Navbar这个组件提到最外层的components文件夹下。

它是一个在各个features当中去进行复用的一个组件,如果是一个features内部所专属的代码,那我们只需要把它放到features所代表的这个文件夹下就可以,那这其实是我们开发者应用的一种常用的目录结构、组织方式。