React性能优化

三个可以优化的地方

避免过度多次渲染 

组件会在以下情况下重新渲染

注意:例如组件组合的形式,<Test><Counter></Counter></Test>,即使Test发生了重新渲染,Counter也不会重新渲染。另外使用React这样的库或框架时,渲染指的是组件函数被调用的过程。这个过程并不一定意味着文档对象模型(DOM)实际上被更新了。它只是意味着组件的逻辑被执行,可能会重新计算组件的状态和属性。

 什么是过度渲染呢?

  • 无效渲染是指组件函数被调用了,但是并没有导致DOM的任何变化。
  • 这通常发生在组件的状态或属性没有改变,但组件仍然被重新渲染的情况下。这种渲染是不必要的,因为它消耗了资源但没有带来任何视觉上的变化。
  • 当然这在react中大部分情况下是没问题的,只有这种情况过度频繁时才会产生问题。

记忆化

组件、对象、函数都可以记忆化。

 memo
工作原理
  1. 创建不会重新渲染的组件

    • memo用于创建一个组件,当其父组件重新渲染时,如果传入的props在两次渲染之间没有变化,那么这个被memo包裹的组件将不会重新渲染。
  2. 只影响props

    • memo只对组件的props进行比较。如果一个被memo包裹的组件在props没有变化的情况下,即使它自己的state发生了变化,或者它订阅的context发生了变化,它仍然会重新渲染。

局限性

  1. 在React中,每次渲染都会重新创建所有内容(包括对象和函数): 这意味着,即使组件的状态没有改变,每次渲染时,组件内部的函数和对象都会被重新实例化。

  2. 在JavaScript中,两个看起来相同的对象或函数实际上是不同的({} != {}): 在JavaScript中,对象和函数是引用类型。即使两个对象的内容完全相同,它们在内存中的地址也是不同的。这意味着,即使两个对象看起来一样,它们也是两个不同的实例。

  3. 因此,如果将对象或函数作为props传递,子组件在每次重新渲染时都会将它们视为新的props: 当父组件将对象或函数作为props传递给子组件时,由于每次渲染都会创建新的实例,子组件会认为这些props是新的,即使它们的值没有变化。

  4. 如果props在重新渲染之间不同,memo将不起作用memo是React的一个优化技巧,它通过比较props来决定是否重新渲染组件。如果props在两次渲染之间没有变化,memo可以防止不必要的渲染。但是,如果props是对象或函数,即使它们的值没有变化,由于它们是新创建的实例,memo也会认为props已经改变,从而导致子组件重新渲染。

所以,我们需要对对象和函数进行memoization(记忆化),以使它们在重新渲染之间保持稳定(保持不变)

useMemo与useCallback
工作原理
  1. 用于记忆化(memoize)对象和函数

  2. 缓存机制

    • 当你将对象或函数传递给 useMemo 或 useCallback 时,这些值或函数会被存储在内存中(即被“缓存”)。在随后的重新渲染中,只要依赖项(即“输入”)没有变化,就会返回缓存的值或函数。
  3. 依赖数组

    • useMemo 和 useCallback 都接受一个依赖数组,这与 useEffect 的工作方式类似。依赖数组用于追踪哪些值或状态影响到了记忆化的值或函数。
    • 如果依赖数组中的任何一个值发生变化,那么记忆化的值或函数就会被重新创建。这是通过比较新旧依赖项来实现的,只有当依赖项发生变化时,才会触发重新计算。

 使用场景
  1. 防止不必要的渲染

    • 通过与 React.memo 一起使用,可以记忆化 props,以避免不必要的组件重新渲染。
  2. 避免每次渲染时的昂贵重新计算

    • 使用 useMemo 来记忆化那些计算成本较高的值。这样,只有在其依赖项发生变化时,才会重新计算这些值,从而节省性能。
  3. 记忆化在其他 Hook 的依赖数组中使用的值

    • 当某个值被用作另一个 Hook(如 useEffect)的依赖数组中的项时,使用 useMemo 或 useCallback 来记忆化这个值可以避免无限循环的副作用。例如,如果你在 useEffect 的依赖数组中直接使用一个会不断变化的值,可能会导致无限循环的副作用执行。通过记忆化这个值,你可以确保只有当值实际改变时,副作用才会重新运行。
案例

假设我们再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组件就起到了作用!

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

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

相关文章

部署项目报错

vue2项目部署后 Error: Cannot find module /views/*** 1.起因 登录页、首页等静态页面可以正常进入&#xff0c;后端访问也正常&#xff0c;可以获取到验证码。 但是登录之后会发现首页空白或者进入不到首页 F12查看有报错信息&#xff1a;Error: Cannot find module ‘/v…

高端空气净化器airgle—甲醛克星 | 双十二选购指南

随着双十二购物节的临近&#xff0c;许多消费者开始关注高端空气净化器的选购。甲醛作为室内空气污染的主要元凶之一&#xff0c;选择一款高效的空气净化器显得尤为重要。本文将详细介绍Airgle高端空气净化器的技术优势及其在除甲醛方面的卓越表现。 甲醛对健康的影响 甲醛超标…

LCR 023. 相交链表

一.题目&#xff1a; LCR 023. 相交链表 - 力扣&#xff08;LeetCode&#xff09; 二.我的原始解法-无&#xff1a; 三.其他人的正确及好的解法&#xff0c;力扣解法参考&#xff1a; 哈希表法及双指针法&#xff1a;LCR 023. 相交链表 - 力扣&#xff08;LeetCode&#xff0…

RocketMq详解:六、RocketMq的负载均衡机制

上一章&#xff1a;《SpringBootAop实现RocketMq的幂等》 文章目录 1.背景1.1 什么是负载均衡1.2 负载均衡的意义 2.RocketMQ消息消费2.1 消息的流转过程2.2 Consumer消费消息的流程 3.RocketMq的负载均衡策略3.1 Broker负载均衡3.2 Producer发送消息负载均衡3.3 消费端的负载均…

02-开发环境搭建

02-开发环境搭建 鸿蒙开发环境的准备主要分为以下环节&#xff1a; 注册开发者实名认证创建应用下载安装开发工具新建工程 注册开发者 在华为开发者联盟网站上&#xff0c;注册成为开发者&#xff0c;并完成实名认证。 打开华为开发者联盟官网&#xff0c;点击“注册”进入…

使用SQLark分析达梦慢SQL执行计划的一次实践

最近刚参加完达梦的 DCP 培训与考试&#xff0c;正好业务系统有个 sql 查询较慢&#xff0c;就想着练练手。 在深入了解达梦的过程中&#xff0c;发现达梦新出了一款叫 SQLark 百灵连接的工具。 我首先去官网大致浏览了下。虽然 SQLark 在功能深度上不如 DM Manager 和 PL/SQ…

Hive分区值的插入

对于Hive分区表&#xff0c;在我们插入数据的时候需要指定对应的分区值&#xff0c;而这里就会涉及很多种情况。比如静态分区插入、动态分区插入、提供的分区值和分区字段类型不一致&#xff0c;或者提供的分区值是NULL的情况&#xff0c;下面我们依次来展现下不同情况下的表现…

云计算vspere 安装过程

1 材料的准备 1 安装虚拟机 vmware workstation 2 安装esxi 主机 3 在esxi 主机上安装windows 2018 dns 服务器 4 在虚拟机上安装windows 2018 服务器 6 安装vcenter 5 登入界面测试 这里讲一下&#xff0c;由于部署vspere 需要在windows 2012 服务器上部…

【0x0001】HCI_Inquiry命令详解

目录 一、命令概述 1.1. 返回事件说明 1.2. 设备报告规则 二、命令格式及参数 2.1. HCI_Inquiry命令格式 2.2. LAP参数 2.3. Inquiry_Length 2.4. Num_Responses 三、响应事件 3.1. HCI_Command_Status 事件 3.2. HCI_Inquiry_Result, HCI_Inquiry_Result_with_RSSI…

五.指派问题

匈牙利发求解指派问题找独立0元素&#xff0c;常用的步骤为&#xff1a;

2024蜀道山高校联合公益赛

mixian 数组越界&#xff0c;可以去攻击stdout泄露libc&#xff0c;之后伪随机数绕过 from pwn import* from struct import pack import ctypes #from LibcSearcher import * from ae64 import AE64 def bug():gdb.attach(p)pause() def s(a):p.send(a) def sa(a,b):p.sendaf…

【若依框架】RuoYi-Vue的前端和后端配置步骤和启动步骤

&#x1f399;告诉你&#xff1a;Java是世界上最美好的语言 &#x1f48e;比较擅长的领域&#xff1a;前端开发 是的&#xff0c;我需要您的&#xff1a; &#x1f9e1;点赞❤️关注&#x1f499;收藏&#x1f49b; 是我持续下去的动力&#xff01; 目录 一. 作者有话说 …

Python毕业设计选题:基于大数据的旅游景区推荐系统_django

开发语言&#xff1a;Python框架&#xff1a;djangoPython版本&#xff1a;python3.7.7数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat11开发软件&#xff1a;PyCharm 系统展示 系统首页界面 用户注册界面 用户登录界面 景点信息界面 景点资讯界面 个人中心界面 …

Endnote 参考文献内容没有按引用顺序进行排序

Endnote 参考文献内容没有按引用顺序进行排序&#xff1a; word论文正文第一个引用就是[4]打头&#xff0c;疯狂卸载重装&#xff0c;修改设置&#xff0c;排查了大半天&#xff0c;最后解决了。 常规解决方案 就是在Endnote 软件里面对outputstyle进行修改&#xff0c;将Biogr…

图像滤波和卷积的不同及MATLAB应用实例

滤波与卷积在图像处理中都是非常重要的运算&#xff0c;但它们有着明显的区别。以下是滤波与卷积的主要不同点&#xff0c;并附带一个MATLAB实例来展示两者在图像处理中的效果差异。 一、滤波与卷积的不同 定义与目的&#xff1a; 1&#xff09;滤波&#xff1a;滤波是一种信…

低级爬虫实现-记录HCIP云架构考试

因工作需要考HCIP云架构&#xff08;HCIP-Cloud Service Solution Architect&#xff09;证书, 特意在淘宝上买了题库&#xff0c; 考过了。 事后得知自己被坑了&#xff0c; 多花了几十大洋。 所以想着在授权期内将题库“爬”下来&#xff0c; 共享给大家。 因为整个过程蛮有…

Scala—Sliding(滑动窗口)用法详解

Scala—Sliding&#xff08;滑动窗口&#xff09;用法详解 Scala 的 sliding 方法在处理集合时&#xff0c;可以方便地获取一个集合的“滑动窗口”&#xff08;能够按照指定的窗口大小和步长从集合中获取子集合&#xff09;。 sliding 方法定义&#xff1a; def sliding(size…

一、理论基础-PSI

之前参加了隐语第2期&#xff0c;对隐语SecretFlow框架有了大致的了解&#xff0c;这次参加隐语第4期&#xff0c;学习下PSI和PIR。 一、PSI定义 首先介绍PSI的定义&#xff0c;PSI&#xff08;隐私集合求交&#xff0c;Private Set Intersection即PSI)是安全多方计算&#x…

11.15【JAVA】【网络编程】【DEBUG】

代码以开源至cqujk/CquJavaEE 的myExp-socketCode分支,欢迎拷打 参考REPO Java 11: Standardized HTTP Client API 没反应 这是因为这应当是两个线程,当server创建好套接字后,进入accept时,就不会继续向下运行,客户端自然也就无法发送请求 首先要保证server进入accept(这个…

国家信息中心单志广:智慧城市转型中的数据要素价值释放

今日&#xff0c;由中国电信集团主办的2024数字科技生态大会数据要素合作论坛在广州市举办。国家发改委国家信息中心信息化和产业发展部主任单志广在论坛发展主旨演讲&#xff1a;智慧城市转型中的数据要素价值释放&#xff0c;主要包括发展新形势、数据新要素、数据新产权、数…