React性能优化
三个可以优化的地方

避免过度多次渲染
组件会在以下情况下重新渲染
注意:例如组件组合的形式,<Test><Counter></Counter></Test>,即使Test发生了重新渲染,Counter也不会重新渲染。另外使用React这样的库或框架时,渲染指的是组件函数被调用的过程。这个过程并不一定意味着文档对象模型(DOM)实际上被更新了。它只是意味着组件的逻辑被执行,可能会重新计算组件的状态和属性。
什么是过度渲染呢?
- 无效渲染是指组件函数被调用了,但是并没有导致DOM的任何变化。
- 这通常发生在组件的状态或属性没有改变,但组件仍然被重新渲染的情况下。这种渲染是不必要的,因为它消耗了资源但没有带来任何视觉上的变化。
- 当然这在react中大部分情况下是没问题的,只有这种情况过度频繁时才会产生问题。
记忆化
组件、对象、函数都可以记忆化。

memo
工作原理
-
创建不会重新渲染的组件:
memo用于创建一个组件,当其父组件重新渲染时,如果传入的props在两次渲染之间没有变化,那么这个被memo包裹的组件将不会重新渲染。
-
只影响props:
memo只对组件的props进行比较。如果一个被memo包裹的组件在props没有变化的情况下,即使它自己的state发生了变化,或者它订阅的context发生了变化,它仍然会重新渲染。

局限性

-
在React中,每次渲染都会重新创建所有内容(包括对象和函数): 这意味着,即使组件的状态没有改变,每次渲染时,组件内部的函数和对象都会被重新实例化。
-
在JavaScript中,两个看起来相同的对象或函数实际上是不同的({} != {}): 在JavaScript中,对象和函数是引用类型。即使两个对象的内容完全相同,它们在内存中的地址也是不同的。这意味着,即使两个对象看起来一样,它们也是两个不同的实例。
-
因此,如果将对象或函数作为props传递,子组件在每次重新渲染时都会将它们视为新的props: 当父组件将对象或函数作为props传递给子组件时,由于每次渲染都会创建新的实例,子组件会认为这些props是新的,即使它们的值没有变化。
-
如果props在重新渲染之间不同,memo将不起作用:
memo是React的一个优化技巧,它通过比较props来决定是否重新渲染组件。如果props在两次渲染之间没有变化,memo可以防止不必要的渲染。但是,如果props是对象或函数,即使它们的值没有变化,由于它们是新创建的实例,memo也会认为props已经改变,从而导致子组件重新渲染。
所以,我们需要对对象和函数进行memoization(记忆化),以使它们在重新渲染之间保持稳定(保持不变)。
useMemo与useCallback
工作原理
-
用于记忆化(memoize)对象和函数
-
缓存机制:
- 当你将对象或函数传递给
useMemo或useCallback时,这些值或函数会被存储在内存中(即被“缓存”)。在随后的重新渲染中,只要依赖项(即“输入”)没有变化,就会返回缓存的值或函数。
- 当你将对象或函数传递给
-
依赖数组:
useMemo和useCallback都接受一个依赖数组,这与useEffect的工作方式类似。依赖数组用于追踪哪些值或状态影响到了记忆化的值或函数。- 如果依赖数组中的任何一个值发生变化,那么记忆化的值或函数就会被重新创建。这是通过比较新旧依赖项来实现的,只有当依赖项发生变化时,才会触发重新计算。

使用场景
-
防止不必要的渲染:
- 通过与
React.memo一起使用,可以记忆化 props,以避免不必要的组件重新渲染。
- 通过与
-
避免每次渲染时的昂贵重新计算:
- 使用
useMemo来记忆化那些计算成本较高的值。这样,只有在其依赖项发生变化时,才会重新计算这些值,从而节省性能。
- 使用
-
记忆化在其他 Hook 的依赖数组中使用的值:
- 当某个值被用作另一个 Hook(如
useEffect)的依赖数组中的项时,使用useMemo或useCallback来记忆化这个值可以避免无限循环的副作用。例如,如果你在useEffect的依赖数组中直接使用一个会不断变化的值,可能会导致无限循环的副作用执行。通过记忆化这个值,你可以确保只有当值实际改变时,副作用才会重新运行。
- 当某个值被用作另一个 Hook(如
案例
假设我们再App.js中有以下对象和函数,使用了useMemo与useCallback:
const [isFakeDark, setIsFakeDark] = useState(false);const [posts, setPosts] = useState(() =>Array.from({ length: 30 }, () => createRandomPost()));const handleAddPost = useCallback(function handleAddPost(post) {setPosts((posts) => [post, ...posts]);}, []);const archiveOptions = useMemo(() => {return {show: false,title: `Post archive in addition to ${posts.length} main posts`,};}, [posts.length]);<ArchivearchiveOptions={archiveOptions}onAddPost={handleAddPost}setIsFakeDark={setIsFakeDark}/>
注意下useMemo与useCallback使用方式的细微差别。
Archive使用memo如下所示:
const Archive = memo(function Archive({ archiveOptions, onAddPost }) {// Here we don't need the setter function. We're only using state to store these posts because the callback function passed into useState (which generates the posts) is only called once, on the initial render. So we use this trick as an optimization technique, because if we just used a regular variable, these posts would be re-created on every render. We could also move the posts outside the components, but I wanted to show you this trick 😉const [posts] = useState(() =>// 💥 WARNING: This might make your computer slow! Try a smaller `length` firstArray.from({ length: 30000 }, () => createRandomPost()));const [showArchive, setShowArchive] = useState(archiveOptions.show);return (<aside><h2>{archiveOptions.title}</h2><button onClick={() => setShowArchive((s) => !s)}>{showArchive ? "Hide archive posts" : "Show archive posts"}</button>{showArchive && (<ul>{posts.map((post, i) => (<li key={i}><p><strong>{post.title}:</strong> {post.body}</p><button onClick={() => onAddPost(post)}>Add as new post</button></li>))}</ul>)}</aside>);
});
注意: 对于state的set函数来说,它不需要useCallback函数,它本身随着渲染就不会改变地址。
减小Bundle大小
Bundle与Bundle分别是什么?

代码分割




代码分割(Code splitting)是一种在现代前端工程中常用的优化技术,它允许将应用程序的代码库分割成多个小块(bundles),这些小块可以独立于主代码库进行加载。这种方法特别适用于大型应用程序,可以显著提高加载速度和性能
路由级别代码分割

转变为

Suspense是一个用于处理异步组件加载的组件。它允许你定义一个边界,当其子组件在加载过程中遇到异步操作(如数据获取)而暂停时,可以显示一个备用内容(fallback)。然后Suspense与React的lazy函数结合使用,实现组件的懒加载。这种方式允许你在组件首次渲染时自动触发组件的加载,同时在加载过程中显示一个占位符。

因为懒加载的元素,当你切换到Login或者Pricing等页面的时候, 对应的js的代码块才刚刚从服务器下载过来,需要时间到达客户端。这个时候suspense组件就起到了作用!
相关文章:
React性能优化
三个可以优化的地方 避免过度多次渲染 组件会在以下情况下重新渲染 注意:例如组件组合的形式,<Test><Counter></Counter></Test>,即使Test发生了重新渲染,Counter也不会重新渲染。另外使用React这样的库或框架时&a…...
前端开发流程实操:从概念到上线
在前端开发这个充满创意与技术挑战的领域,一个清晰的开发流程是确保项目顺利进行并达到预期效果的关键。 下面就和大家分享一下前端开发的实操流程。 一、项目启动与需求分析 前端开发不是孤立的,它是整个项目的一部分,所以首先要与项目团…...
Metasploit使用
最近在学Metasploit,Metasploit是一个免费的、可下载的渗透测试框架,通过它可以很容易地获取、开发并对计算机软件漏洞实施攻击,是一个集成了渗透测试全流程的渗透工具。 图一 模块:模块组织按照不同的用途分为7种类型的模块 &am…...
Milvus向量数据库05-常见问题整理
Milvus向量数据库05-常见问题整理 1-什么是PipeLine 这张图展示了一个文档处理和搜索系统的架构,主要分为两个部分:Ingestion Pipeline(摄取管道)和 Search Pipeline(搜索管道)。下面是对图中各部分的详细…...
Ruby On Rails 笔记3——表的增删改查
1.Migration Migrations是一种便利的方法,能以重现的方式随时间推移改变数据库schema. 使用Ruby Domain Specific Language (DSL),因此你不用手写SQL,进而使你的schema和changes与数据库独立。 可以把每次migration看作是数据库的一个新“版本”。A schema开始时什么都没有…...
CSS3 动画详解,介绍、实现与应用场景详解
CSS3 动画概述 CSS3 动画是通过 CSS3 的新特性来实现元素的动态变化。与传统的 JavaScript 动画不同,CSS3 动画主要通过 CSS 属性的变化来实现动画效果,具有高效、轻量和易于实现的优点。CSS3 动画通常用于网页的动态交互效果、过渡效果、元素移动、缩放、旋转等场景。 一、…...
Winston-MySQL 使用文档
目录 简介 安装 配置 环境变量配置 日志级别和表配置 创建 Logger 实例 文件传输配置 控制台输出配置 完整代码 使用方法 记录信息日志 记录错误日志 记录警告日志 总结 简介 winston-mysql 是一个为 winston3.x 日志库设计的 MySQL 传输插件,允许你…...
java日期工具: 获取两个时间段的时间段值,Java获得两个日期之间的所有年、月份、日。
文章目录 日期字符串格式化获取两个日期之间的所有日期 (字符串格式)获取两个时间段的时间段值,Java获得两个日期之间的所有年、月份、日。生效时间需要大于当前时间结束时间的月份不能大于当前月份日期字符串格式化 /*** 日期字符串格式化** @param time* @param Format_int…...
【Rive】混合动画
1 混合动画简介 【Rive】动画 中介绍了 Rive 中动画的基础概念和一般动画的制作流程,本文将介绍混合动画的基础概念和一般制作流程。Unity 中混合动画介绍详见→ 【Unity3D】动画混合。 混合动画是指同一时刻多个动画按照一定比例同时执行,这些动画控制的…...
qt应用程序崩溃日志和转储dmp文件对于定位问题
qt应用程序崩溃日志和转储文件对于定位问题 一. DMP 文件包含的信息:二. 分析 DMP 文件的主要方法:三. 生成更详细的 DMP 文件:四. 分析 DMP 文件的注意事项:五. 实用建议:六. 实战 一. DMP 文件包含的信息:…...
Mysql架构
连接层 最上层是一些客户端和连接服务,负责客户端的连接,验证账号密码等授权认证 服务层 主要完成大多数的核心服务功能,对sql进行解析,优化,调用函数,如果是查询操作,有没有缓存等操作操作。所…...
杂发单的单据类型一个参数的逻辑
【核准中可改】被产线滥用了。它们可以这样做,开立一张杂发单,打印出来交领导层签名。单据要交财务做核算的。然后去修改杂发单的材料。以为可以瞒天过海。2个仓库,一个中掉坑里,一个发现了它们的拙劣的手段,上报之后没…...
Linux系统 vim 编辑文件搜索关键字用法
1、首先确保在normal模式下,按ESC后不在insert模式 输入 /test或?test 此时就会匹配 test 字符串,并且高亮显示 2、向前搜索 /字符串:按n匹配下一个目标,按N匹配上一个目标 3、向后搜索 ?字符串:按n匹配上一个目标…...
Vue智慧商城项目
创建项目 vue组件库 — vant-ui(常用于移动端) Vant 2 - 轻量、可靠的移动端组件库 安装vant npm i vantlatest-v2 -S 引入组件 按需导入和全部导入 全部导入 整个组件库的所有组件都导进来,缺点是增加了代码包体积 main.js import…...
Qt Window应用程序去掉控制台窗口
Qt Window应用程序去掉控制台窗口 方式一 set(PROJECT_SOURCESWIN32main.cppmainwindow.hpp )add_executable(Tool-V2${PROJECT_SOURCES} )方式二 set_target_properties(Tool-V2 PROPERTIESMACOSX_BUNDLE TRUEWIN32_EXECUTABLE TRUE )参考文献: cmake Qt 项目…...
软件测试最新项目合集【商城、外卖、银行、金融等等.......】
项目一:ShopNC商城 项目概况: ShopNC商城是一个电子商务B2C电商平台系统,功能强大,安全便捷。适合企业及个人快速构建个性化网上商城。 包含PCIOS客户端Adroid客户端微商城,系统PC后台是基于ThinkPHP MVC构架开发的跨…...
SAP SD学习笔记18 - 投诉处理4 - 请求书订正依赖,投诉处理流程的总结
上一章讲了 Credit/Debit Memo依赖,Credit/Debit Memo。Credit Memo依赖 本质上是一张受注票;Credit Memo 本质上是一张请求票。 SAP SD学习笔记17 - 投诉处理3 - Credit/Debit Memo依赖,Credit/Debit Memo-CSDN博客 本章继续讲本图中的内容…...
VBA批量提取PDF内容的程序
VBA批量提取PDF内容的程序 Sub ExtractPDFText()Dim pdfApp As Acrobat.AcroAppDim pdfDoc As Acrobat.CAcroPDDocDim pdfPage As Acrobat.AcroPDPageDim txtData As StringDim i As IntegerDim filePath As StringDim outputFolder As StringDim outputFileName As String 初…...
C++入门终
目录 一、引用 二、内联函数 三、auto关键字 四、指针空值nullptr 一、引用 引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间 类型&引用变量名(对象名)…...
ubuntu下Qt5自动编译配置QtMqtt环境(10)
文章目录 [toc]1、概述2、下载QtMqtt源码3、编译4、验证5、参考6、视频 更多精彩内容👉内容导航 👈👉Qt网络编程 👈 1、概述 Qt默认是不包含mqtt库的,如果需要使用到mqtt库就只能自己编译配置; 网络所有的…...
解锁你的音乐宝藏:ncmdump让网易云音乐文件自由播放
解锁你的音乐宝藏:ncmdump让网易云音乐文件自由播放 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 当你精心收藏的网易云音乐只能在特定客户端播放时,那种被束缚的感觉是否让你感到无奈?想象一下…...
开源机械爪控制库:从PID算法到ROS集成的全栈开发指南
1. 项目概述:一个开源的机械爪设计与控制库最近在机器人硬件开发的圈子里,开源项目“MeyerZhou/openclaw”引起了不少创客和机器人爱好者的注意。简单来说,这是一个专注于机械爪(或称机械手、夹爪)设计与控制的代码库和…...
Unity游戏开发集成MCP协议:AI助手自动化操作指南
1. 项目概述:Unity游戏开发中的MCP革命如果你是一名Unity开发者,最近可能已经注意到一个名为“CoderGamester/mcp-unity”的项目在GitHub上悄然走红。这不仅仅是一个普通的插件或工具包,它代表了一种全新的工作流范式,旨在将大型语…...
MySQL 视图使用场景与限制
视图是把查询封装成「虚拟表」的方式,用对了简化查询,用错了性能爆炸。这篇说说视图的用法和注意事项。 什么是视图? -- 视图:保存好的 SQL 查询,像表一样使用 CREATE VIEW view_name AS SELECT column1, column2 FROM…...
MySQL 索引底层 B+ 树原理
聊 MySQL 索引,不讲 B 树,那就是在耍流氓。 大家好,我是乱码字符。今天咱们深入聊聊 MySQL 索引的底层数据结构——B 树。这篇文章能让你彻底搞明白,为什么有时候明明加了索引,查询却还是慢成狗。 先说说为什么要用树结…...
【Midjourney数字艺术风格终极指南】:20年AI视觉专家亲授7大核心风格参数调优法则(含V6.1新增Realism Mode实测数据)
更多请点击: https://intelliparadigm.com 第一章:Midjourney数字艺术风格演进与V6.1核心变革 Midjourney自V1发布以来,其图像生成范式经历了从纹理模拟到语义理解、从风格模仿到跨模态协同的深层跃迁。V6.1标志着模型首次在原生架构中集成…...
AI Agent架构深度解析:从核心原理到工程实践
1. 项目概述:一次关于AI Agent的深度技术探险最近在GitHub上看到一个名为“tvytlx/ai-agent-deep-dive”的项目,光看标题就让人眼前一亮。这显然不是一个简单的“Hello World”式教程,而是一次对AI Agent(智能体)技术的…...
AI全栈开发实战:基于Cursor的智能代码生成与架构设计
1. 项目概述:当AI代码助手遇上全栈开发最近在GitHub上看到一个挺有意思的项目,叫“Cursor-FullStack-AI-App”。光看名字,你大概能猜到它和Cursor这个AI代码编辑器有关,并且涉及全栈应用开发。但它的价值远不止于此。作为一个在前…...
从单体智能到组织智能:AgentOrg多智能体系统架构与实战
1. 项目概述:从单体智能到组织智能的范式跃迁最近在AI Agent领域,一个名为“AgentOrg”的开源项目引起了我的注意。这个由Angelopvtac发起的项目,其核心思想非常吸引人:它不再将AI Agent视为一个孤立的、执行单一任务的智能体&…...
Sophia优化器:二阶曲率感知如何加速大模型训练与调参
1. 项目概述:当优化器遇上“二阶”智慧最近在复现一些前沿的论文实验时,我又一次被优化器的选择给卡住了。AdamW虽然稳,但在某些超大规模模型或特定任务上,总觉得收敛速度不够快,调参又是个玄学。就在我对着损失曲线发…...
