如何在 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>;
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/75713.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ffmpeg-将多个视频切片成一个新的视频

使用 ffmpeg 工具可以轻松完成将多个视频切片合并为一个新的视频。以下是实现这一目标的具体步骤和命令。 步骤概览 1、将多个视频切片。 2、创建文本文件列出切片的视频片段。 3、使用 ffmpeg 合并这些切片为一个新的视频。 一&#xff1a;安装 ffmpeg 确保你的系统中已经安…

【第2月_day10】Pandas数据查看与选择

以下是专为小白设计的 Pandas数据查看与选择 学习内容&#xff0c;从基础到应用逐步讲解&#xff0c;附带清晰示例和注意事项&#xff1a; 一、数据查看&#xff1a;快速了解你的数据 1. head() 和 tail() 作用&#xff1a;查看数据的前几行或后几行&#xff0c;默认显示5行。…

Jetpack LiveData 使用与原理解析

一、引言 在 Android 开发中&#xff0c;数据的变化需要及时反映到界面上是一个常见的需求。然而&#xff0c;传统的方式可能会导致代码复杂、难以维护&#xff0c;并且容易出现内存泄漏等问题。Jetpack 组件中的 LiveData 为我们提供了一种优雅的解决方案&#xff0c;它是一种…

Unity2D 五子棋 + Photon联网双人对战

开发环境配置 Unity版本2022.3 创建Photon账号以及申请Photon中国区服务 官网申请账号&#xff1a;Multiplayer Game Development Made Easy Photon Engine 中国区服务&#xff1a; 光子引擎photonengine中文站 成都动联无限科技有限公司(vibrantlink.com) 导入PUN2插件以及…

(UI自动化测试web端)第二篇:元素定位的方法_css定位之属性选择器

看代码里的【find_element_by_css_selector( )】( )里的表达式怎么写&#xff1f; 文章介绍了第四种写法属性选择器 &#xff0c;你要根据网页中的实际情况来判断自己到底要用哪一种方法来进行元素定位。每种方法都要多练习&#xff0c;全都熟了之后你在工作当中使用起来元素定…

预编译能否 100%防 sql 注入?

&#x1f31f; 什么是 SQL 注入&#xff1f; SQL 注入&#xff08;SQL Injection&#xff09;是指攻击者利用特殊输入&#xff0c;让数据库执行它本来不应该执行的代码&#xff0c;从而获取或篡改数据。 就像在考试的时候偷偷改题目&#xff0c;让老师改成你想要的内容&#…

第十五章 | Layer2、Rollup 与 ZK 技术实战解析

&#x1f4da; 第十五章 | Layer2、Rollup 与 ZK 技术实战解析 ——构建下一代高性能区块链应用&#xff0c;从 Solidity 到 zkSync&#xff01; ✅ 本章导读 Layer2 和零知识证明&#xff08;ZK&#xff09;正成为区块链发展的核心方向。 随着主网 Gas 居高不下、TPS 无法满…

2025-03-26 学习记录--C/C++-PTA 6-3 求链式表的表长

合抱之木&#xff0c;生于毫末&#xff1b;九层之台&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。&#x1f4aa;&#x1f3fb; 一、题目描述 ⭐️ 6-3 求链式表的表长 本题要求实现一个函数&#xff0c;求链式表的表长。 函数接口定义&#xff1a; &…

【Linux】Linux_Ubuntu与Windows之间的文件传输

一、Linux终端命令的复制粘贴 1.打开linux 终端&#xff0c;输入以下命令&#xff1a;&#xff08;注意&#xff0c;需要联网&#xff09; 2.命令行下载&#xff1a; sudo apt-get autoremove open-vm-tools 3.命令行安装&#xff1a; sudo apt-get install open-vm-tools-…

Python Sanic面试题及参考答案

目录 Sanic 的事件循环机制与 uvloop 的关系 Sanic 的 Request/Response 对象生命周期如何管理?如何访问请求上下文? 对比 Sanic 与 Flask/Django 的异步处理模型差异 Sanic 的 Blueprint 机制如何实现模块化路由?如何处理跨蓝图中间件? 如何在 Sanic 中实现 WebSocket…

算法每日一练 (18)

&#x1f4a2;欢迎来到张翊尘的技术站 &#x1f4a5;技术如江河&#xff0c;汇聚众志成。代码似星辰&#xff0c;照亮行征程。开源精神长&#xff0c;传承永不忘。携手共前行&#xff0c;未来更辉煌&#x1f4a5; 文章目录 算法每日一练 (18)删除并获得点数题目描述解题思路解题…

VsCode启用右括号自动跳过(自动重写) - 自录制gif演示

VsCode启用右括号自动跳过(自动重写) - 自录制gif演示 前言 不知道大家在编程时候的按键习惯是怎样的。输入完左括号后编辑器一般会自动补全右括号&#xff0c;输入完左括号的内容后&#xff0c;是按→跳过右括号还是按)跳过右括号呢&#xff1f; for (int i 0; i < a.s…

用Python和Stable Diffusion生成AI动画:从图像到视频的全流程指南

引言 本文将演示如何通过Python代码实现基于文本提示的AI动画生成。我们将使用Stable Diffusion生成连贯图像帧,结合OpenCV合成视频,最终实现一个可自定义的动画生成 pipeline。 一、环境准备 1. 依赖安装 # 安装核心库 pip install diffusers transformers torch numpy …

【Git 常用指令速查表】

Git 常用指令速查表 Git 常用指令速查表目录1. 初始化仓库2. 提交代码流程3. 分支管理4. 远程仓库操作5. 撤销操作6. 查看状态与日志7. 其他实用指令完整操作示例常用场景速查表 Git 常用指令速查表 目录 初始化仓库提交代码流程分支管理远程仓库操作撤销操作查看状态与日志其…

分布式爬虫框架Scrapy-Redis实战指南

引言 在当今数字化的时代背景下&#xff0c;互联网技术的蓬勃兴起极大地改变了旅游酒店业的运营模式与市场格局。作为旅游产业链中的关键一环&#xff0c;酒店业的兴衰与互联网技术的应用程度紧密相连。分布式爬虫技术&#xff0c;尤其是基于 Scrapy 框架的 Scrapy-Redis 扩展…

爬虫:scrapy面试题大全(60个scrapy经典面试题和详解)

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 1. 什么是Scrapy?2. Scrapy 框架的组件及其作用?3. Scrapy的工作流程是什么?(运行机制)4. 如何创建一个Scrapy项目?5. 如何定义一个Spider?6. 如何在Scrapy中提取数据?7. Scrapy中的Item是什么?8. Scrapy中的P…

Leetcode12-整数转罗马数字

题目链接&#xff1a;12. 整数转罗马数字 - 力扣&#xff08;LeetCode&#xff09; 看题目限制输入1 < num < 3999&#xff0c;就直接用暴力法写了&#xff0c;还比较简单 代码&#xff1a; char* intToRoman(int num) {char *res (char*)malloc(100);int index 0;i…

WebMvcConfigurer 的 addResourceLocations

在 Spring Boot 的 addResourceLocations 方法中&#xff0c;file: 是一个 URL 前缀&#xff0c;用于指示资源的位置是本地文件系统路径。以下是详细解释&#xff1a; 一、file: 的作用 file: 是 Java 中用于表示本地文件系统的 URL 前缀。它告诉 Spring Boot&#xff0c;资源…

Spring Boot响应压缩配置与优化

一、核心工作机制 1.1 自动协商触发条件 Spring Boot的响应压缩功能基于智能协商机制&#xff0c;需同时满足以下条件方可触发&#xff1a; 客户端支持&#xff1a;请求头包含Accept-Encoding: gzip/deflate数据量阈值&#xff1a;响应体大小超过预设值&#xff08;默认2KB&…

JavaScript 改变 HTML 样式

JavaScript 改变 HTML 样式 JavaScript 改变 HTML 样式的核心是通过操作 DOM 元素的 CSS 属性或 类名 实现动态视觉效果。以下是具体方法与场景解析: 一、直接修改元素的 style 属性 通过 DOM 元素的 style 属性直接设置内联样式,优先级最高: // 修改单个样式 document.…