当前位置: 首页 > article >正文

如何在 React 项目中使用React.lazy和Suspense实现组件的懒加载?

大白话如何在 React 项目中使用React.lazy和Suspense实现组件的懒加载?

在 React 项目里,有时候组件功能多、体积大,要是一次性把所有组件都加载进来,网页加载速度就会变慢。而 React 提供了 React.lazySuspense 这两个好东西,能让我们实现组件的懒加载,也就是需要用到某个组件的时候再去加载它,这样可以加快网页的初始加载速度。接下来,我就详细说说怎么用这俩来实现组件懒加载。

1. 创建项目

首先,你得有个 React 项目。要是还没有,就可以用下面这个命令快速创建一个:

npx create-react-app lazy-loading-example
cd lazy-loading-example

2. 创建要懒加载的组件

src 目录下创建一个新的组件文件,比如叫 LazyComponent.js,这个组件就是我们要懒加载的对象。下面是这个组件的代码:

// 导入 React 库
import React from 'react';// 定义一个函数组件 LazyComponent
const LazyComponent = () => {// 返回一个包含文本的 div 元素return <div>这是一个懒加载的组件</div>;
};// 导出这个组件,以便其他文件可以使用它
export default LazyComponent;

3. 使用 React.lazySuspense 实现懒加载

src 目录下的 App.js 文件里,我们要使用 React.lazySuspense 来实现组件的懒加载。下面是具体的代码:

// 导入 React 库,同时引入 React.lazy 和 Suspense
import React, { lazy, Suspense } from 'react';// 使用 React.lazy 动态导入 LazyComponent 组件
// React.lazy 接收一个函数,这个函数返回一个动态导入组件的 Promise
const LazyComponent = lazy(() => import('./LazyComponent'));// 定义 App 函数组件
const App = () => {return (<div><h1>组件懒加载示例</h1>{/* 使用 Suspense 包裹懒加载的组件 */}{/* fallback 属性指定在组件加载过程中显示的内容 */}<Suspense fallback={<div>正在加载组件...</div>}>{/* 渲染懒加载的组件 */}<LazyComponent /></Suspense></div>);
};// 导出 App 组件,作为项目的根组件
export default App;

代码解释

  • React.lazy:它就像是一个小助手,专门负责在需要的时候去加载组件。你给它一个函数,这个函数返回一个动态导入组件的 Promise,它就会在合适的时候去加载这个组件。
  • Suspense:它就像一个缓冲器,在组件加载的过程中,它会显示你设置的 fallback 内容,比如“正在加载组件…”,等组件加载好了,再把组件显示出来。

4. 运行项目

最后,用下面的命令启动项目:

npm start

当你打开浏览器访问这个项目的时候,一开始会看到“正在加载组件…”,等组件加载完成,就会看到“这是一个懒加载的组件”。

通过上面这些步骤,你就学会了如何在 React 项目中使用 React.lazySuspense 实现组件的懒加载啦。这样做可以让你的网页加载速度更快,用户体验也会更好。

除了React.lazy和Suspense,还有哪些实现组件懒加载的方法?

除了 React.lazySuspense,以下是几种在 React 里实现组件懒加载的方法:

1. 手动控制导入

可以通过手动管理组件的导入和渲染来实现懒加载。在组件需要渲染的时候,动态地导入相应的组件。

import React, { useState } from 'react';const App = () => {// 用于存储懒加载组件的状态const [LazyComponent, setLazyComponent] = useState(null);// 加载组件的函数const loadComponent = async () => {try {// 动态导入组件const { default: component } = await import('./LazyComponent');// 更新状态以存储导入的组件setLazyComponent(component);} catch (error) {console.error('加载组件时出错:', error);}};return (<div><button onClick={loadComponent}>加载组件</button>{LazyComponent && <LazyComponent />}</div>);
};export default App;

在上述代码中,loadComponent 函数在按钮点击时被调用,它会动态导入 LazyComponent,并将其存储在状态中。之后,当 LazyComponent 存在于状态中时,就会渲染该组件。

2. 使用第三方库 react-loadable(旧版)

react-loadable 是一个第三方库,它简化了 React 中组件的懒加载过程。不过需要注意的是,这个库已经不再维护,在 React 16.6 及以后版本中,官方推荐使用 React.lazySuspense

首先,安装 react-loadable

npm install react-loadable

然后,使用它来实现懒加载:

import React from 'react';
import Loadable from 'react-loadable';// 定义加载时显示的组件
const LoadingComponent = () => <div>正在加载...</div>;// 使用 react-loadable 创建懒加载组件
const LazyComponent = Loadable({loader: () => import('./LazyComponent'),loading: LoadingComponent,
});const App = () => {return (<div><h1>组件懒加载示例</h1><LazyComponent /></div>);
};export default App;

在这段代码中,Loadable 函数接收一个对象,其中 loader 属性是一个返回动态导入组件的函数,loading 属性指定了在组件加载过程中显示的组件。

3. 基于路由的懒加载

在使用 React Router 进行路由管理时,可以实现基于路由的懒加载。这样当用户访问特定路由时,才加载对应的组件。

import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';// 懒加载 Home 组件
const Home = lazy(() => import('./Home'));
// 懒加载 About 组件
const About = lazy(() => import('./About'));const App = () => {return (<Router><Suspense fallback={<div>正在加载...</div>}><Routes><Route path="/" element={<Home />} /><Route path="/about" element={<About />} /></Routes></Suspense></Router>);
};export default App;

这里,当用户访问不同的路由时,对应的组件才会被动态加载。Suspense 组件用于在加载过程中显示提示信息。

对比React.lazy和Suspense以及手动控制导入这三种方式的优缺点

以下是对 React.lazy 和 Suspense 以及手动控制导入这三种组件懒加载方式优缺点的对比:

React.lazy 和 Suspense

优点
  • 语法简洁React.lazySuspense 是 React 官方提供的懒加载解决方案,使用起来语法简洁直观。例如,使用 React.lazy 只需一行代码就能定义一个懒加载组件,Suspense 也能很方便地设置加载时的占位内容。
const LazyComponent = lazy(() => import('./LazyComponent'));
<Suspense fallback={<div>Loading...</div>}><LazyComponent />
</Suspense>
  • 与 React 生态集成良好:作为 React 官方特性,它能与 React 的其他特性(如 React Router)无缝集成,方便在路由层面实现懒加载,使代码结构更清晰。
const Home = lazy(() => import('./Home'));
<Route path="/" element={<Suspense fallback={<div>Loading...</div>}><Home /></Suspense>
} />
  • 自动处理错误和加载状态Suspense 可以自动处理组件加载过程中的状态,当组件加载失败时,也可以结合 ErrorBoundary 来捕获和处理错误,增强了应用的健壮性。
缺点
  • 兼容性依赖 React 版本React.lazySuspense 是 React 16.6 及以上版本才支持的特性,如果项目使用的是旧版本的 React,则无法使用该功能。
  • 灵活性相对较低:在某些复杂场景下,React.lazySuspense 的默认行为可能无法满足需求,例如需要更精细地控制组件加载时机。

手动控制导入

优点
  • 高度灵活:手动控制导入允许你完全自主地控制组件的加载时机和方式。你可以根据不同的条件(如用户操作、数据加载状态等)来决定何时加载组件,适用于各种复杂的业务场景。
const [LazyComponent, setLazyComponent] = useState(null);
const loadComponent = async () => {const { default: component } = await import('./LazyComponent');setLazyComponent(component);
};
<button onClick={loadComponent}>Load Component</button>
  • 兼容性好:这种方式不依赖于特定的 React 版本,只要支持动态导入语法,就可以在任何 React 项目中使用。
缺点
  • 代码复杂度高:手动控制导入需要编写更多的代码来管理组件的加载状态和错误处理,代码结构会变得复杂,维护成本较高。
const loadComponent = async () => {try {const { default: component } = await import('./LazyComponent');setLazyComponent(component);} catch (error) {console.error('Failed to load component:', error);// 还需要额外处理错误状态}
};
  • 缺乏统一的加载状态管理:不像 Suspense 可以统一管理加载状态和占位内容,手动控制导入需要自己实现加载状态的管理,容易出现不一致的情况。

除了懒加载,还有哪些优化React项目性能的方法?

除了懒加载,以下是一些优化 React 项目性能的常用方法:

1. 虚拟列表

当需要渲染大量数据列表时,一次性渲染所有数据会导致性能问题。虚拟列表只渲染当前可见区域的数据,当用户滚动列表时,动态地加载和渲染新的数据。

import React from 'react';
import { FixedSizeList } from 'react-window';const Row = ({ index, style }) => (<div style={style}>这是第 {index} 行数据</div>
);const App = () => {return (<FixedSizeListheight={400}width={300}itemSize={30}itemCount={1000}>{Row}</FixedSizeList>);
};export default App;

这里使用了 react-window 库的 FixedSizeList 组件,它会根据列表的高度、宽度、每个项的大小和项的总数,只渲染当前可见区域的项。

2. 使用 shouldComponentUpdatePureComponentReact.memo

shouldComponentUpdate

在类组件中,可以通过 shouldComponentUpdate 生命周期方法来控制组件是否需要重新渲染。通过比较前后的 propsstate,决定是否阻止组件的重新渲染。

class MyComponent extends React.Component {shouldComponentUpdate(nextProps, nextState) {// 比较前后的 props 和 state,返回 false 则阻止重新渲染return this.props.someProp!== nextProps.someProp || this.state.someState!== nextState.someState;}render() {return <div>{this.props.someProp}</div>;}
}
PureComponent

PureComponent 是 React 提供的一个基类,它会自动对 propsstate 进行浅比较,如果没有变化则阻止组件重新渲染。

import React, { PureComponent } from 'react';class MyPureComponent extends PureComponent {render() {return <div>{this.props.someProp}</div>;}
}
React.memo

对于函数组件,可以使用 React.memo 来实现类似的功能。React.memo 是一个高阶组件,它会对组件的 props 进行浅比较,只有当 props 发生变化时才会重新渲染组件。

import React from 'react';const MyFunctionComponent = React.memo((props) => {return <div>{props.someProp}</div>;
});

3. 优化事件处理函数

在 React 中,每次渲染时创建新的事件处理函数会导致不必要的性能开销。可以在类组件的构造函数中绑定事件处理函数,或者使用箭头函数定义事件处理函数。

class MyComponent extends React.Component {constructor(props) {super(props);this.handleClick = this.handleClick.bind(this);}handleClick() {// 处理点击事件}render() {return <button onClick={this.handleClick}>点击我</button>;}
}

4. 优化 CSS 样式

避免使用内联样式,因为内联样式会在每次渲染时重新计算和应用。可以使用 CSS 类名来管理样式,这样浏览器可以更好地缓存和优化样式。

import './styles.css';const MyComponent = () => {return <div className="my-style">这是一个组件</div>;
};

5. 代码分割和打包优化

合理地进行代码分割,将不常用的代码分离到单独的包中,减少初始加载的代码量。可以使用 Webpack 等打包工具的配置来实现代码分割,例如使用动态导入语法。

const loadComponent = async () => {const { default: MyComponent } = await import('./MyComponent');// 使用组件
};

6. 使用 useCallbackuseMemo

useCallback

useCallback 用于缓存函数,避免在每次渲染时创建新的函数实例。当函数作为 props 传递给子组件时,使用 useCallback 可以避免子组件不必要的重新渲染。

import React, { useCallback } from 'react';const MyComponent = () => {const handleClick = useCallback(() => {// 处理点击事件}, []);return <button onClick={handleClick}>点击我</button>;
};
useMemo

useMemo 用于缓存计算结果,避免在每次渲染时进行重复的计算。当某个计算结果依赖于某些值,并且这些值没有变化时,使用 useMemo 可以直接返回之前的计算结果。

import React, { useMemo } from 'react';const MyComponent = ({ a, b }) => {const sum = useMemo(() => a + b, [a, b]);return <div>总和是: {sum}</div>;
};

相关文章:

如何在 React 项目中使用React.lazy和Suspense实现组件的懒加载?

大白话如何在 React 项目中使用React.lazy和Suspense实现组件的懒加载&#xff1f; 在 React 项目里&#xff0c;有时候组件功能多、体积大&#xff0c;要是一次性把所有组件都加载进来&#xff0c;网页加载速度就会变慢。而 React 提供了 React.lazy 和 Suspense 这两个好东西…...

绿色暴政:Relax Max如何用军工科技定义环保新标准

《绿色暴政&#xff1a;Relax Max如何用军工科技定义环保新标准》 ——从隐形战斗机涂层到零碳卫浴的降维打击 &#xff08;洛克希德马丁实验室&#xff0c;2023年&#xff09;当F-35战斗机的隐形涂料配方被改写为卫浴釉料时&#xff0c;环保产业迎来了最硬核的颠覆者。Relax…...

蓝桥杯刷题 Day 4 栈与链表

蓝桥杯刷题 Day 4 栈与链表 文章目录 蓝桥杯刷题 Day 4 栈与链表前言一、栈1. 解题思路2. 拆解代码&#xff08;不复杂&#xff0c;不拆了&#xff09; 二、链表1. 解题思路1.1 主函数1.2 自定义列表类1.2.1 插入操作1.2.2 删除操作1.2.3 按要求输出 三、 题后收获3.1 知识点 前…...

第十三届蓝桥杯单片机省赛程序设计试题

目录 试题 各程序块代码 init.c main.c other.h other.c key.c seg.c onewire.c部分 ds1302.c部分 试题 各程序块代码 init.c #include "other.h"void init74hc138(unsigned char n){P2(P2&0x1f)|(n<<5);P2&0x1f; } void init(){P00x00;in…...

QOpenGLWidget动态加载功能实现教程(Qt+OpenGL)

QOpenGLWidget动态加载功能实现教程 我需要在Qt里面使用QOpenGLWidget显示OpenGL窗口&#xff0c;并且需要实现加载模型后重新渲染更新窗口的功能&#xff0c;但是一直无法更新被卡住了&#xff0c;现在把问题解决了总结一下整个实现过程。 创建一个自己的OpenGLWidget类 QOp…...

机器学习正则化技术:Ridge、Lasso与ElasticNet全解析

机器学习中的正则化技术 在机器学习中&#xff0c;正则化技术&#xff08;如 Ridge 和 Lasso&#xff09;主要用于解决过拟合问题&#xff0c;通过限制模型复杂度提高泛化能力。以下是详细说明及实例代码&#xff1a; 一、正则化解决的问题 过拟合&#xff1a;模型在训练集表…...

数字转换(c++)

【题目描述】 如果一个数 xx 的约数和 yy &#xff08;不包括他本身&#xff09;比他本身小&#xff0c;那么 xx 可以变成 yy &#xff0c;yy 也可以变成 xx 。例如 44 可以变为 33 &#xff0c;11 可以变为 77 。限定所有数字变换在不超过 nn 的正整数范围内进行&#xff0c;…...

ESP32驱动BMP280和MQ4传感器

文章目录 前言 一、硬件准备 所需组件 连接方式&#xff1a; 二、软件实现 1.所需库 2.代码实现 效果演示 三、上传Qt端 前言 在物联网和环境监测应用中&#xff0c;传感器是获取环境数据的关键组件。本文将详细介绍如何使用ESP32微控制器同时驱动BMP280大气压力传感器…...

洛谷题单1-B2002 Hello,World!-python-流程图重构

题目描述 编写一个能够输出 Hello,World! 的程序。 提示&#xff1a; 使用英文标点符号&#xff1b;Hello,World! 逗号后面没有空格。H 和 W 为大写字母。 输入格式 无 输出格式 无 输入输出样例 #1 输入 #1 无输出 #1 Hello,World!方式-print() 代码 class Solut…...

MQTT协议笔记

消息格式 MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;是一种轻量级的消息协议&#xff0c;专为低带宽、高延迟或不可靠的网络设计&#xff0c;广泛应用于物联网&#xff08;IoT&#xff09;设备之间的通信。MQTT消息体的结构遵循MQTT协议规范&#xff0…...

CentOS系统下安装tesseract-ocr5.x版本

CentOS系统下安装tesseract-ocr5.x版本 安装依赖包&#xff1a; yum update -y yum install autoconf automake libtool libjpeg-devel libpng-devel libtiff-devel zlib-devel yum install automake libtool bzip2 -y手动编译安装GCC&#xff08;因系统默认安装的GCC版本比较…...

“征服HTML引号恶魔:“完全解析手册”!!!(quot;表示双引号)

&#x1f6a8;&#x1f4e2; "征服HTML引号恶魔&#xff1a;“完全解析手册” &#x1f4e2;&#x1f6a8; &#x1f3af; 博客引言&#xff1a;当引号变成"恶魔" &#x1f631; 是否遇到过这种情况&#xff1a; 写HTML时满心欢喜输入<div title"他…...

如何使用VS中的Android Game Development Extension (AGDE) 来查看安卓 Logcat 日志

一、首先按照以下 指引 中的 第1、2步骤&#xff0c;安装一下 AGDE &#xff0c;AGDE 的安装包可以在官网上找到。 UE4 使用AndroidGameDevelopmentExtension&#xff08;AGDE&#xff09;对安卓客户端做“断点调试”与“代码热更”-CSDN博客 在执行第二步骤前&#xff0c;记得…...

VSCode 生成HTML 基本骨架

在VSCode 新建html文件中敲一个英文感叹号 ! <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><titl…...

【Spring AI】基于专属知识库的RAG智能问答小程序开发——功能优化:用户鉴权相关工具类代码

系列文章目录 【Spring AI】基于专属知识库的RAG智能问答小程序开发——完整项目&#xff08;含完整前端后端代码&#xff09;【Spring AI】基于专属知识库的RAG智能问答小程序开发——代码逐行精讲&#xff1a;核心ChatClient对象相关构造函数【Spring AI】基于专属知识库的R…...

Solr-搜索引擎-入门到精通

以下是对 Apache Solr 的简介及其常用语法的快速入门指南&#xff1a; 一、Solr 是什么&#xff1f; • 核心定位&#xff1a;Apache Solr 是一个基于 Lucene 的高性能、开源的搜索平台&#xff0c;支持全文检索、分词、高亮、聚合统计等功能。 • 核心功能&#xff1a; • 全…...

07_GRU模型

GRU模型 双向GRU笔记:https://blog.csdn.net/weixin_44579176/article/details/146459952 概念 GRU&#xff08;Gated Recurrent Unit&#xff09;也称为门控循环单元&#xff0c;是一种改进版的RNN。与LSTM一样能够有效捕捉长序列之间的语义关联&#xff0c;通过引入两个&qu…...

【字符设备驱动开发–IMX6ULL】(二)Linux 设备号

【字符设备驱动开发–IMX6ULL】&#xff08;二&#xff09;Linux 设备号 文章目录 【字符设备驱动开发–IMX6ULL】&#xff08;二&#xff09;Linux 设备号1 设备号的组成2.设备号的分配 1 设备号的组成 为了方便管理&#xff0c;Linux 中每个设备都有一个设备号&#xff0c;设…...

【大模型基础_毛玉仁】3.4 Prompt 技巧

目录 3.4 Prompt 技巧3.4.1 规范Prompt 编写1&#xff09;任务说明要明确2&#xff09;上下文丰富且清晰3&#xff09;输出格式要规范4&#xff09;排版要清晰 3.4.2 合理归纳提问1&#xff09;复杂问题拆解2&#xff09;追问 3.4.3 适时使用CoT1&#xff09;何时使用CoT2&…...

探索PyMOL新插件NRGSuite-Qt:全面提升分子对接、结合位点预测与动力学模拟的研究效率

随着分子建模和计算生物学的快速发展&#xff0c;分子对接&#xff08;Molecular Docking&#xff09;、结合位点预测、相互作用分析以及动力学研究等领域的工具越来越重要。这些工具不仅帮助研究人员理解分子间的相互作用机制&#xff0c;还能加速药物设计和优化过程。NRGSuit…...

sql2022 复制 事务级别发布后无法删除

Cannot execute as the database principal because the principal "dbo" does not exist, this type of principal cannot be impersonated, or you do not have permission. 用SA用户登录执行下列语句 USE [xxxxx] GO EXEC dbo.sp_changedbowner loginame Nsa, …...

wokwi arduino mega 2560 - 键盘与LCD显示

截图&#xff1a; 链接&#xff1a; https://wokwi.com/projects/414520193913760769 代码&#xff1a; //cslg lcd key #include <LiquidCrystal.h> // 引入LiquidCrystal库&#xff0c;用于LCD显示 #include <Keypad.h> // 引入Keypad库&#xff0c;用于键盘输…...

Linux设置SSH免密码密钥登录

文章目录 设置SSH免密码密钥登录第一步&#xff1a; 生成SSH密钥对&#xff08;在客户端操作&#xff09;方式一&#xff1a;Windows 10/11 内置的 OpenSSH 客户端&#xff08;推荐&#xff09;常用选项&#xff1a;密钥算法选择建议生成秘钥 方式二&#xff1a;借用Xshell工具…...

深度剖析HTTP协议—GET/PUT请求方法的使用-构造请求的方法

活动发起人小虚竹 想对你说&#xff1a; 这是一个以写作博客为目的的创作活动&#xff0c;旨在鼓励大学生博主们挖掘自己的创作潜能&#xff0c;展现自己的写作才华。如果你是一位热爱写作的、想要展现自己创作才华的小伙伴&#xff0c;那么&#xff0c;快来参加吧&#xff01…...

GPU算力哪家好?GpuGeek推出高性能GPU云服务

在人工智能和深度学习领域&#xff0c;GPU算力租赁已成为推动技术创新的关键因素。随着越来越多的企业和个人开发者投身于AI研究和应用开发&#xff0c;如何高效、灵活地获取GPU算力成为了一个亟待解决的问题。GpuGeek作为一站式AI基础设施平台&#xff0c;凭借其独特的优势&am…...

蓝桥杯算法实战分享

蓝桥杯算法实战分享 蓝桥杯是国内知名的程序设计竞赛&#xff0c;涵盖算法、数据结构、编程技巧等多个领域。本文将从实战角度分享蓝桥杯算法竞赛的常见题型、解题思路和优化技巧&#xff0c;帮助参赛者更好地备战。 1. 常见题型与解题思路 蓝桥杯的题型主要包括以下几类&…...

【每日算法】Day 9-1:贪心算法精讲——区间调度与最优选择(C++实现)

掌握高效决策的核心思想&#xff01;今日深入解析贪心算法的底层逻辑&#xff0c;聚焦区间调度与最优选择两大高频场景&#xff0c;结合大厂真题与严谨证明&#xff0c;彻底掌握“局部最优即全局最优”的算法哲学。 一、贪心算法核心思想 贪心算法&#xff08;Greedy Algorit…...

构建稳健的机器学习系统:应对数据偏移挑战

构建稳健的机器学习系统&#xff1a;应对数据偏移挑战 1. 引言&#xff1a;数据偏移类型与挑战 在机器学习系统从实验室到生产环境的转变过程中&#xff0c;数据偏移&#xff08;Data Shift&#xff09;是最常见也最具挑战性的问题之一。所谓数据偏移&#xff0c;指的是训练数…...

从零构建大语言模型全栈开发指南:第二部分:模型架构设计与实现-2.1.3前馈网络(FFN)与激活函数(GELU)优化

👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 文章大纲 2.1.3 前馈网络(FFN)与激活函数(GELU)优化1. 前馈网络(FFN)的架构设计与数学原理1.1 FFN在Transformer中的核心作用2. GELU激活函数的数学特性与优化2.1 GELU的数学形式与近似计算3. 逐行代码实现…...

3个版本的Unity项目的异同

根据搜索结果&#xff0c;以下是关于 SPR 3D Sample Scene(URP)、SPR Universal 3D 和 3D(Built-In Render Pipeline) 的定义及区别分析&#xff1a; 1. 定义与用途 SPR 3D Sample Scene(URP) 是基于 Universal Render Pipeline (URP) 的 3D 示例场景&#xff0c;专为展示 URP …...