前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >大爱并发模式!React Router 路由跳转最佳实践的秘密

大爱并发模式!React Router 路由跳转最佳实践的秘密

作者头像
用户6901603
发布2024-06-07 20:43:48
990
发布2024-06-07 20:43:48
举报
文章被收录于专栏:不知非攻不知非攻

在 Next.js 大热之前,React Router 是 React 生态中,最流行的路由库。也是我最喜爱的路由库。不过随着版本的迭代,React Router 变得越来越庞大了。他的复杂度已经快要比得上一个框架了。

所以也不知道现在大家是否还在使用它。

本文主要的目的是结合 Suspense 与 useTransition,来为大家分享一下路由懒加载如何做才是最佳实践。技术点主要包含如下内容

  • 1、React Router v6 基础简介
  • 1、React.lazy
  • 2、Suspense
  • 3、useTransition

全文共 3028 字,预计阅读需要花费 6 分钟

1、React Router v6 基础简介

浏览器支持了两种路由方案。分别是 history router 与 hash router。

history router 是目前的主流方案,他相对简洁,我们可以通过 location.pathname 获取到对应的值。

代码语言:javascript
复制
// history router
xxx.com/article/121
xxx.com/profile

hash router 是指 # 后面的内容。可以通过 location.hash 获取到对应的值。

代码语言:javascript
复制
// hash router
xxx.com#/article/121
xxx.com#/profile

React Router 中,分别有两个顶层容器组件对应不同的路由模式。<BrowserRouter> 对应 history router,<HashRouter> 对应 hash router.

在项目顶层组件中,我们只需要使用对应的组件包裹项目节点,就可以使用对应的路由模式。例如,我们的 demo 项目使用了 BrowserRouter

代码语言:javascript
复制
ReactDOM.createRoot(document.getElementById('root')).render(
  <StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </StrictMode>
)

然后我们就可以在 App 中使用 <Routes> 组件来配置子路由。Routes 表示当前组件的一个路由适配标记,当路由发生变化时,它会自动去识别子路由中是否有合适的组件被匹配上了。

子路由的配置,我们使用如下语法来完成

代码语言:javascript
复制
<Route path="tasks" element={<DashboardTasks />} />

path 表示当前路由,element 表示当前路由所对应需要渲染的组件。

当子路由配置比较多时,我们可以通过抽象的思路,将其中的配置项抽离成为数组,然后通过 map 遍历来实现功能

代码语言:javascript
复制
const routerConfig = [{
  path: 'tasks',
  element: DashboardTasks
}, {
  ...
}]
代码语言:javascript
复制
{routerConfig.map((item, index) => {
  <Route key={item.path} path={item.path} element={
    <item.element />
  } />
))}

如果还有其他更细节的逻辑,请结合正常的需求和 JS 逻辑完善补充,切勿生搬硬套。例如,Route 还支持子组件嵌套,那么这里的逻辑会变得更复杂

两种常见的路由跳转方案

我们可以使用 Link 组件来实现跳转,它类似与一个 a 标签,是一个正常的 UI 组件,因此我们只需要把他放到跳转按钮应该存在的位置即可。

代码语言:javascript
复制
import { Link } from "react-router-dom";

function UsersIndexPage({ users }) {
  return (
    <div>
      <h1>Users</h1>
      <ul>
        {users.map((user) => (
          <li key={user.id}>
            <Link to={user.id}>{user.name}</Link>
          </li>
        ))}
      </ul>
    </div>
  );
}

另外一种方式就是利用 js 来控制跳转。React Router v6 中,提供了新的 hook 来支持这种跳转。

代码语言:javascript
复制
import {useNavigate} from 'react-router-dom'

function Motion() {
  const navigate = useNavigate()

  function __handler() {
    navigate('/use/01')
  }

  return (
    <div>
      <button onClick={__handler}>点击跳转</button>
    </div>
  )
}

export default Motion;

虽然 React Router v6 非常复杂,不过利用我们刚才提到的知识点,已经可以勉强搭建一个小型应用了。

2、React.lazy

当项目变得庞大时,我们可以通过 React.lazy 来进行拆包。有 React.lazy 引入的组件会单独的打成一个包。如果我们的每一个页面组件都使用它来引入,那么,主包的大小就不会随着页面变多也变大。

这是首屏优化的重要手段之一。

我们可以单独引入一个组件

代码语言:javascript
复制
import React from 'react';
const OtherComponent = React.lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
    <div>
      <OtherComponent />
    </div>
  );
}

在新的 React 版本中,可以直接将其当做正常的组件使用即可,不会报错。

代码语言:javascript
复制
<Router 
  path="xxx" 
  element={<OtherComponent />} 
/>

也可以在刚才抽离出来的配置文件中引入。

代码语言:javascript
复制
import {lazy} from 'react'

export const navigation = [{
  path: '',
  name: 'home',
  component: lazy(() => import('./pages/home'))
}, {
  path: 'motion',
  name: 'react motion',
  component: lazy(() => import('./pages/00_motion'))
}, {
  ...
}]

如果我们不担心在加载时的白屏时间过长,那么这样做就可以了。

i通常情况下也不会太长,大多数页面代码都非常小,一闪而过就加载成功了

3、Suspense

当然,更保险和稳妥的做法是,使用 Suspense 做一层兜底。Suspense 可以一定程度上拦截可能会发生的报错行为,并且我们有机会在加载页面时,显示一个 Loading 过程。

代码语言:javascript
复制
<!--map 中-->
<Route key={item.path} path={item.path} element={
  <Suspense fallback={<div>loading...</div>}>
    <item.component />
  </Suspense>
} />

加了这个之后,我们来看一下页面切换的演示效果

注意看,组件首次加载时,会显示我们在 Suspense 中设定的 Loading 状态。但是当我们第二次点击时,Loading 就不再显示。

因此,这种交互效果的体验还是非常可以了。许多团队搞到这里基本上就差不多了。

4、进一步结合 useTransition 使用

但是这里我们注意到,每个页面的整体体积是非常小的。有的甚至只有不到 200B,打包之后还会变得更小,因此新的页面组件模块加载非常快。

大多数情况下,增加一个 Loading 表示加载过程其实是没有必要的。因此,我们这里可以进一步结合 useTransition 来让 Suspense 的 Loading 不显示。

注意,这个行为是一个可选的,并非必要,当你觉得部分页面加载还是需要花费一点时间,那么显示 Loading 可能是更好的选择

具体的做法,就是使用 useTransition 降低路由跳转的优先级,让加载行为先执行。

完整代码如下。

代码语言:javascript
复制
import {useTransition} from 'react'
import {useNavigate} from 'react-router-dom'

function Motion() {
  const [isPending, startTransition] = useTransition()
  const navigate = useNavigate()

  function __handler() {
    startTransition(() => {
      navigate('/use/01')
    })
  }

  return (
    <div>
      <button
        onClick={__handler}
        disabled={isPending}
      >点击跳转</button>
    </div>
  )
}

export default Motion;

我们可以观察一下这种方式的路由切换效果。

在上面的演示图中我们可以看到,由于新页面模块的请求非常快,因此切换的过程也非常丝滑,基本上看不出来有任何卡顿。

5、总结

在以前的开发中,大家对于 React 的并发模式,更多停留在有所耳闻的阶段。他具体是如何运用到实践的许多道友感受并不深刻,甚至有的人认为这玩意儿压根没什么用。

但是在以后的开发中,并发模式将会更加的亲民,我们会越来越多的在实践中感受到它的存在。

在本次案例中,代码执行顺序上,我们会先执行路由跳转,再执行页面模块的请求任务。但是我们通过 useTransition 降低路由跳转的优先级,让他在请求任务之后执行。

因此最终的结果是请求完成之后再跳转,我们就发现当跳转发生时,页面组件已经准备好了。那么 Loading 就可以不用出现。由于请求速度非常快,因此用户也不会感受到明显的卡顿。

在代码组织上,也非常的方便,我们并没有为了让请求先发生,就极大的调整代码逻辑结构,而是只需要让本应该先发生的任务,降低优先级,让后来的任务插队执行。

希望能够通过这案例,让道友们能 get 到并发模式的强大魅力。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-05-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 这波能反杀 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、React Router v6 基础简介
  • 2、React.lazy
  • 3、Suspense
  • 4、进一步结合 useTransition 使用
  • 5、总结
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档