Suspense及lazy()懒加载

本文深入探讨React中Suspense及lazy()懒加载原理,解析其在代码分割、动态组件加载及异步请求处理中的作用,揭示React未来发展方向。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

React中Suspense及lazy()懒加载原理和使用的理解
Suspense和lazy()都是react中比较新的特性,在项目中使用还比较少,但是学习一下有助于在后面的项目中使用,同样可以一窥React未来的发展方向

React.lazy()
概括
顾名思义lazy()方法是用来对项目代码进行分割,懒加载用的.只有当组件被加载,内部的资源才会导入

为什么需要懒加载
在React的项目中import导入其他组件和库都是默认在初始直接导入的,webpack等打包工具会将import导入的文件直接合并到一个大文件中,如果项目很大,打包完后初始化加载时需要加载的文件会很大,这时候就需要代码分割

官方文档中的例子

项目中:

// app.js
import { add } from './math.js';

console.log(add(16, 26)); // 42
// math.js
export function add(a, b) {
  return a + b;
}

打包后

function add(a, b) {
  return a + b;
}

console.log(add(16, 26)); // 42

如何进行代码分割
在你的应用中引入代码分割的最佳方式是通过动态 import() 语法,这是官方文档中说的

动态import例子:

静态导入:

import { add } from './math';

console.log(add(16, 26));

动态导入:

import("./math").then(math => {
  console.log(math.add(16, 26));
});

使用了动态导入之后,webpack检测到这种语法会自动代码分割,也就是压缩到两个文件里

React.lazy()就是对这个种动态导入方式的优化方法
使用:

const OtherComponent = React.lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
    // Displays <Spinner> until OtherComponent loads
    <React.Suspense fallback={<Spinner />}>
      <div>
        <OtherComponent />
      </div>
    </React.Suspense>
  );
}

发现没有原来的动态导入写法像 Promise的写法链式调用,现在动态导入的方式,有点类似于Async写出来是同步使用的,可以直接讲返回的Promise对象作为组件使用,当这个组件pending是显示的是Suspense中fallback的内容,只有resolve才显示加载好的组件.

所以可以看出Suspense和React.lazy()需要结合在一起用,否则会报错缺少Placeholder UI`

Suspense
Suspense的英文意思是悬念,悬停**,Suspense的作用就是在遇到异步请求或者异步导入组件的时候等待请求和导入完成再进行渲染,**相比普通的组件, 我们是要求render是一个纯函数,一旦开始渲染不会等待,而有了Suspense后我们可以再render过程中写一部代码.

Suspense应用场景
Subspense存在两种应用场景,第一种就是动态导入组件(如上),一种就是异步请求数据(暂时不支持,大概16.9版本)

动态导入组件
动态导入组件上面的例子就是上面的代码片段,就是当这个组件pending是显示的是Suspense中fallback的内容,只有resolve才显示加载好的组件,所以fallback不能为空

优点
好处在于我们可以不用创建一些组件状态的变量来控制是否显示loading画面和真正组件,这部分逻辑直接由Suspense内部实现. 而且还有一种场景就是当一个父组件中,有多个动态加载的组件,Suspense可以直接将loading状态聚合,只有当所有组件加载完成才显示,这里免去了复杂的逻辑判断.

数据请求后渲染页面
Suspense暂时还不支持数据请求后渲染, 预计是在16.9版本也就是2019年年中发布,但是以及有了实例使用的方法,下面这里就是官方的示例代码,这里做一些翻译解释

// unstable_createResource这个就是一个封装的请求数据的插件,不用太清楚类似于fetch
import {unstable_createResource} from 'react-cache';

// 声明请求数据的方法
const TodoResource = unstable_createResource(fetchTodo);

//内部请求TodoResource.read(props.id) 就是异步请求数据
function Todo(props) {
  // Suspends until the data is in the cache
  const todo = TodoResource.read(props.id);
  return <li>{todo.title}</li>;
}

function App() {
  return (
    // 只有当两个Todo内部的异步请求都完成后才能渲染出来,否则渲染<Spinner/>
    <React.Suspense fallback={<Spinner />}>
      <ul>
        {/* Siblings fetch in parallel */}
        <Todo id="1" />
        <Todo id="2" />
      </ul>
    </React.Suspense>
  );
}

这就是Suspense请求数据时的使用的方法,同样解决了loading状态的问题,相当于再render过程中加入了异步副作用操作,再普通的组件中异步操作是不起作用的,因为先渲染完,异步数据才会返回,这时候已经渲染完了.

Suspense实现原理
Subspense的实现主要就是利用了**ComponentDidCatch这个生命周期,这个什么周期就是用来捕获子组件树中的任何Javascript异常**

源码就不分析了,这里说一下大概的流程步骤:

父组件渲染到子组件时发现异步请求,直接抛出错误,捕获的结果是一个Promise对象
ComponentDidCatch捕获这个Promise对象,pending状态下渲染fallback的
当resolve时重新render,遇到下一个异步请求重复上面操作
直到整个父组件的抛出的promise对象都为resolve,将loading替换为真正的组件.
总结
Suspense其实就是将原来放在外面处理的异步请求也就是副作用放到渲染过程中进行操作,这样render这个函数就不再是纯函数了,但是非常直观方便,不需要再用很多状态来控制loading显示,而异步请求的结果无法预测会导致很多bug.等到Suspense支持数据请求的场景时,我会考虑把它运用到自己的项目中, 感觉确实方便很多本来就觉得Loading状态有点多余,虽然现在用的是Dva,会自动给effect创建loading状态的,还不是特别需要.


转自:https://blog.youkuaiyun.com/deng1456694385/article/details/88999842

<think>我们正在讨论React中的路由懒加载实现。根据用户的问题,他们想了解如何通过React的lazy函数和Suspense组件来实现路由懒加载。根据引用[1][2][3]中的示例,我们可以总结出实现步骤:1.使用`lazy`函数动态导入组件:`constComponent =lazy(()=> import('./path/to/Component'))`2.在路由配置外层包裹`Suspense`组件,并提供一个`fallback`属性,用于在加载过程中显示加载指示(如Loading...)。3.在`Suspense`内部配置路由,例如使用`Route`组件。注意点: -懒加载的组件必须是默认导出(export default)。-使用`Suspense`是为了在组件加载过程中显示回退内容,避免空白页面。 -如果使用ReactRouter,通常结合`Routes`和`Route`(注意引用中使用了Switch,但新版本推荐使用Routes和Route,且Switch已过时)。我们将按照以下结构回答:1.解释路由懒加载的概念和好处。2.给出实现步骤和代码示例。3.说明注意事项。同时,根据系统指令,我们需要在行内数学表达式(如果有)使用$...$,独立公式用$$...$$(但这里可能不需要数学公式),以及生成相关问题。但是,用户的问题是关于React路由懒加载的,不涉及数学表达式,因此我们主要关注代码和文字描述。另外,注意引用标识:在回答中引用参考内容的地方添加[^1][^2][^3]。</think>### React 路由懒加载实现方法 在 React 中实现路由懒加载主要使用 `lazy` 函数和 `Suspense` 组件,核心写法如下: ```jsx import { lazy, Suspense } from 'react'; import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; // 1. 使用 lazy() 动态导入组件 const Home = lazy(() => import('./pages/Home')); const Article = lazy(() => import('./pages/Article')); function App() { return ( <Router> {/* 2. 用 Suspense 包裹路由 */} <Suspense fallback={<div>Loading...</div>}> <Routes> {/* 3. 配置懒加载路由 */} <Route path="/" element={<Home />} /> <Route path="/article" element={<Article />} /> </Routes> </Suspense> </Router> ); } ``` #### 关键实现要点: 1. **动态导入**:使用 `lazy(() => import('组件路径'))` 语法替代静态导入 2. **加载状态**:通过 `Suspense` 的 `fallback` 属性设置加载指示器 3. **路由配置**:在 `Routes/Route` 中正常使用懒加载组件 #### 注意事项: 1. 懒加载组件必须使用 `export default` 导出[^3] 2. `Suspense` 必须包裹所有懒加载路由组件 3. 推荐配合 `Switch` 使用(旧版)或 `Routes`(v6+)确保单一匹配[^2] 4. 避免在组件内部使用 `lazy()`,应在模块顶层调用 #### 优势: - 减少初始包体积,提升首屏加载速度 - 按需加载路由组件资源 - 改善大型应用性能体验 > 当用户访问 `/article` 路径时,才会动态加载 Article 组件的代码,加载期间显示 `fallback` 内容[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值