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

react hooks--React.memo

基本语法

React.memo 高阶组件的使用场景说明:

React 组件更新机制:只要父组件状态更新,子组件就会无条件的一起更新。

  • 子组件 props 变化时更新过程:组件代码执行 -> JSX Diff(配合虚拟 DOM)-> 渲染(变化后的内容)【 DOM 操作】。
  • 子组件 props 无变化更新过程:组件代码执行 -> JSX Diff(配合虚拟 DOM)【无 DOM 操作】。

注意:此处更新指的是组件代码执行、JSX 进行 Diff 操作(纯 JS 的操作,速度非常快,不会对性能产生太多影响)。

  • 如果组件 props 改变了,那么,该组件就必须要更新,才能接收到最新的 props。
  • 但是,如果组件 props 没有改变时,组件也要进行一次更新。实际上,这一次更新是没有必要的。

如果要避免组件 props 没有变化而进行的不必要更新(Diff),这种情况下,就要使用 React.memo 高阶组件。

注:对于 class 组件来说,可以使用 PureComponent 或 shouldComponentUpdate 钩子函数来实现

import { useState } from 'react'
import ReactDOM from 'react-dom'const Child2 = ({ count }) => {console.log('Child2 子组件代码执行了')return <div style={{ backgroundColor: '#abc' }}>子组件2:{count}</div>
}const Child1 = () => {console.log('Child1 子组件代码执行了')return <div style={{ backgroundColor: '#def' }}>子组件1</div>
}const App = () => {const [count, setCount] = useState(0)return (<div style={{ backgroundColor: 'pink', padding: 10 }}><h1>计数器:{count}</h1><button onClick={() => setCount(count + 1)}>+1</button><hr />{/* 子组件 */}<Child1 /><br /><Child2 count={count} /></div>)
}export default App

语法:

使用场景:当你想要避免函数组件 props 没有变化而产生的不必要更新时,就要用到 React.memo 了。

作用:记忆组件上一次的渲染结果,在 props 没有变化时复用该结果,避免函数组件不必要的更新

解释:

  • React.memo 是一个高阶组件,用来记忆(memorize)组件
  • 参数(Child):需要被记忆的组件,或者说是需要避免不必要更新的组件。
  • 返回值(MemoChild):React 记住的 Child 组件。

原理:通过对比检查更新前后 props 是否相同,来决定是否复用上一次的渲染结果

  • 如果相同,复用上一次的渲染结果;
  • 如果不同,重新渲染组件。

并不是所有的组件都适合使用memo,比如child2组件,每次都需要重新渲染,使用memo反而会使性能变得更低,逻辑也变得更复杂

基本用法

如果你的组件在相同 props 的情况下渲染相同的结果,那么你可以通过将其包装在 React.memo 中调用,以此通过记忆组件渲染结果的方式来提高组件的性能表现。这意味着在这种情况下,React 将跳过渲染组件的操作并直接复用最近一次渲染的结果

React.memo 仅检查 props 变更。如果函数组件被 React.memo 包裹,且其实现中拥有 useStateuseReduceruseContext 的 Hook,当 state 或 context 发生变化时,它仍会重新渲染。

默认情况下,React.memo 只会对更新前后的 props 进行浅对比(shallow compare)与 PureComponent 相同。

也就是说,对于对象类型的 prop 来说,只会比较引用

  • 如果更新前后的引用相同,复用上一次的渲染结果(不会重新渲染该组件)。
  • 如果更新前后的引用不同,重新渲染该组件。

默认情况下其只会对复杂对象做浅层对比,如果你想要控制对比过程,那么请将自定义的比较函数通过第二个参数传入来实现

如果你要手动控制比较过程,可以使用 React.memo 的第二个参数:

解释:

  • 第二个参数:用来比较更新前后 props 的函数。
  • 返回值:如果返回 true,表示记住(不重新渲染)该组件;如果返回 false,表示重新渲染该组件。

子组件Callback.jsx

export default function Callback() {console.log('callback')return (<div>callback</div>)
}

父组件App.jsx:

import Callback from './components/Callback'
import {useState} from "react";export default function App() {const [age, setAge] = useState(20);function changeAge() {setAge(age + 1)}return (<div>age: {age}<button onClick={changeAge}>修改age</button><Callback /></div>)
}

修改父组件的state值后,函数子组件内部的代码运行了,相对而言有点费性能

优化如下:

使用React.memo包裹子组件,缓存上一次的结果,默认情况下其只会对复杂对象做浅层对比,如果你想要控制对比过程,那么请将自定义的比较函数通过第二个参数传入来实现。

子组件Callback.jsx

import React from 'react';function Callback() {console.log('callback')return (<div>callback</div>)
}++ export default React.memo(Callback)

优化后,父组件的state数据变更后,没有执行打印结果。

在父组件中定义个fn函数传入到子组件中:

import Callback from './components/Callback'
import { useState} from "react";export default function App() {console.log('app')const [age, setAge] = useState(20);function changeAge() {setAge(age + 1)}function fn() {}return (<div>age: {age}<button onClick={changeAge}>修改age</button><Callback fn={fn} /></div>)
}

此时,父组件的state数据改变后,会引起子组件的内部代码运行。打印了结果,相对而言性能有损耗。

优化如下:

useCallback优化性能

fn函数通过useCallback缓存起来

import Callback from './components/Callback'
import {useCallback, useState} from "react";export default function App() {console.log('app')const [age, setAge] = useState(20);function changeAge() {setAge(age + 1)}let fn = useCallback(() => {}, [])return (<div>age: {age}<button onClick={changeAge}>修改age</button><Callback fn={fn} /></div>)
}

此时修改父组件的state数据没有引起子组件的内部代码运行

因为fn函数被缓存了,地址没有发生改变,React.memo就认为props数据没有发生改变,所以没有表要重新运行函数。

useCallback如何做的性能优化?

  • 在函数组件中,定义的一般的普通函数在每次组件更新渲染时都会重新生成一个函数,此时函数地址发生改变了,就会引起子组件内部代码运行,损耗性能。
  • 优化:使用useCallback将函数缓存,每次组件更新渲染时,这个函数地址没有发生改变,所以传入到子组件的props数据没有发生发生改变,所以子组件内部代码没有重新执行。
  • React.memo是数据的浅对比,也就是地址的对比,只要传入参数地址发生改变就会重新执行子组件的代码。

总结

useMemo 用于缓存一些耗时的计算结果(返回值),只有当依赖项改变时才重新进行计算。 useCallback(func, [deps]) 等同于 useMemo(() => func, [deps]) useCallback 缓存的是方法的引用,useMemo 缓存的是方法的返回值,适用场景都是避免不必要的子组件渲染。 在类组件中有 React.PureComponent,与之对应的函数组件可以使用 React.memo,它们都会在自身 re-render 时,对每一个 props 项进行浅对比,如果引用没有发生改变,就不会触发渲染。 那么,useMemo 和 React.memo 有什么共同点呢?前者可以在组件内部使用,可以拥有比后者更细粒度的依赖控制。它们两个与 useCallback 的本质一样,都是进行依赖控制。

相关文章:

react hooks--React.memo

基本语法 React.memo 高阶组件的使用场景说明&#xff1a; React 组件更新机制&#xff1a;只要父组件状态更新&#xff0c;子组件就会无条件的一起更新。 子组件 props 变化时更新过程&#xff1a;组件代码执行 -> JSX Diff&#xff08;配合虚拟 DOM&#xff09;-> 渲…...

App端测——稳定性测试

稳定性测试项&#xff1a;Crash、ANR、OOM、内存泄漏 crash&#xff1a;应用崩溃&#xff0c;从提测后开始关注&#xff0c;monkey持续上报跟踪 ANR&#xff1a;系统无响应&#xff0c;使用低端机内存小的机型测试&#xff0c;及monkey中关注ANR问题。关于ANR详细&#xff1a…...

[数据结构与算法·C++] 笔记 1.4 算法复杂性分析

1.4 算法复杂性分析 算法的渐进分析 数据规模 n 逐步增大时, f(n)的增长趋势当 n 增大到一定值以后&#xff0c;计算公式中影响最大的就是 n 的幂次最高的项其他的常数项和低幂次项都可以忽略 大O表示法 函数f&#xff0c;g定义域为自然数&#xff0c;值域非负实数集定义: …...

Hive parquet表通过csv文件导入数据

1. background 已建好了 hive parquet 格式的表, 需要从服务器的csv导入数据至该hive表 2. step 提前上传csv至服务器 /path/temp.csv 创建 textfile 格式的中转表(这里使用内部表,方便删除) ,源表名dw_procurement.dwd_tc_comm_plant ,这里中转表加上了csv后缀 CREATE TA…...

C++ 构造函数最佳实践

文章目录 1. 构造函数应该做什么1.1 初始化成员变量1.2 分配资源1.3 遵循 RAII 原则1.4 处理异常情况 2. 构造函数不应该做什么2.1 避免做大量的工作2.2 不要在构造函数中调用虚函数2.3 避免在构造函数中执行复杂的初始化逻辑2.4 避免调用可能抛出异常的代码 3. 构造函数的其他…...

C++——关联式容器(4):set和map

在接触了诸如二叉搜索树、AVL树、红黑树的树形结构之后&#xff0c;我们对树的结构有了大致的了解&#xff0c;现在引入真正的关联式容器。 首先&#xff0c;先明确了关联式容器的概念。我们之前所接触到的如vector、list等容器&#xff0c;我们知道他们实际上都是线性的数据结…...

Spring Mybatis 基本使用 总结

1. 简介 Mybatis库可以简化数据库的操作&#xff0c;专注于sql语句。 2.搭建步骤 2.1 在pom.xml引入mybatis <dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.11</version> </dep…...

接口幂等性和并发安全的区别?

目录标题 幂等性并发安全总结 接口幂等性和并发安全是两个不同的概念&#xff0c;虽然它们在设计API时都很重要&#xff0c;但侧重点不同。 幂等性 定义&#xff1a;幂等性指的是无论对接口进行多少次相同的操作&#xff0c;结果都是一致的。例如&#xff0c;HTTP的PUT和DELE…...

【记录一下VMware上开虚拟端口映射到公网】

材料 win11 和装在vmware上的ubuntu 步骤一在Ubuntu上配置静态地址&#xff0c;配置如下 vim /etc/netplan/01-network-manager-all.yaml(此文件看系统上对应的是哪个文件&#xff0c;建议先备份)network:version: 2renderer: NetworkManagerethernets:ens33:dhcp4: falseadd…...

半导体器件制造5G智能工厂数字孪生物联平台,推进制造业数字化转型

半导体器件制造行业作为高科技领域的核心驱动力&#xff0c;正积极探索和实践以5G智能工厂数字孪生平台为核心的新型制造模式。这一创新不仅极大地提升了生产效率与质量&#xff0c;更为制造业的未来发展绘制了一幅智能化、网络化的宏伟蓝图。 在半导体器件制造5G智能工厂中&a…...

数据结构之存储位置

p 和 "hello,world"存储在内存哪个区域&#xff1f;( ) (鲁科安全) int main() { char *p "hello,world"; return 0; } p是栈区&#xff0c;”hello,world”是.ro段 一个由C/C编译的程序&#xff0c;会将占用的内存分为几个部分&#xff1a;堆、栈、代…...

传输层协议(TCP和UDP)

目录 一、UDP 1、UDPAPI 2、UDPAPI的使用 二、TCP 1、TCPAPI 2、TCP的相关特性 2.1 确认应答 2.2 超时重传 2.3 连接管理&#xff08;三次握手&#xff0c;四次挥手&#xff09; 2.4 滑动窗口 2.5 流量控制 2.6 拥塞控制 2.7 延时应答 2.8 捎带应答 2.9 面向字节…...

智能仓库|基于springBoot的智能无人仓库管理设计与实现(附项目源码+论文+数据库)

私信或留言即免费送开题报告和任务书&#xff08;可指定任意题目&#xff09; 目录 一、摘要 二、相关技术 三、系统设计 四、数据库设计 五、核心代码 六、论文参考 七、源码获取 一、摘要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xf…...

2.《DevOps》系列K8S部署CICD流水线之部署NFS网络存储与K8S创建StorageClass

架构 服务器IP服务名称硬件配置192.168.1.100k8s-master8核、16G、120G192.168.1.101k8s-node18核、16G、120G192.168.1.102k8s-node28核、16G、120G192.168.1.103nfs2核、4G、500G操作系统:Rocky9.3 后续通过K8S部署GitLab、Harbor、Jenkins 一、环境准备 #关闭防火墙开机自…...

【数据仓库】数据仓库常见的数据模型——维度模型

文章部分图参考自&#xff1a;多维数据模型各种类型&#xff08;星型、雪花、星座、交叉连接&#xff09; - 知乎 (zhihu.com) 文章部分文字canla一篇文章搞懂数据仓库&#xff1a;四种常见数据模型&#xff08;维度模型、范式模型等&#xff09;-腾讯云开发者社区-腾讯云 (ten…...

【Kubernetes】常见面试题汇总(三十)

目录 82. Worker 节点宕机&#xff0c;简述 Pods 驱逐流程。 特别说明&#xff1a; 题目 1-68 属于【Kubernetes】的常规概念题&#xff0c;即 “ 汇总&#xff08;一&#xff09;~&#xff08;二十二&#xff09;” 。 题目 69-113 属于【Kubernetes】的生产应用题。 8…...

【Web】PolarCTF2024秋季个人挑战赛wp

EZ_Host 一眼丁真命令注入 payload: ?host127.0.0.1;catf* 序列一下 exp: <?phpclass Polar{public $lt;public $b; } $pnew Polar(); $p->lt"system"; $p->b"tac /f*"; echo serialize($p);payload: xO:5:"Polar":2:{s:2:"…...

职业技能大赛-自动化测试笔记分享-2

一、时间等待处理 1、强制等待(无条件等待) 使用方法:time.sleep(delay) delay的单位为秒,delay设置多少秒页面就会等待多长时间,容易让线程挂掉,使程序抛异常,所以要慎用此方法。 #导入强制等待模块 import time from selenium import webdriverwd = webdriver.Chro…...

LeetCode讲解篇之1343. 大小为 K 且平均值大于等于阈值的子数组数目

文章目录 题目描述题解思路题解代码 题目描述 题解思路 题目让我们求长度为k的子数组并且该子数组的平均值大于threshold&#xff0c;对于这题&#xff0c;我们可以考虑维护一个长度为k的窗口&#xff0c;窗口不断向右滑动&#xff0c;遍历所有长度为k的子数组&#xff0c;我们…...

电子元件制造5G智能工厂物联数字孪生平台,推进制造业数字化转型

5G智能工厂与物联数字孪生平台的融合应用&#xff0c;不仅为电容器制造业注入了新的活力&#xff0c;更为整个制造业的数字化转型树立了新的标杆。电子元件制造过程中&#xff0c;数字孪生平台通过实时监测生产线的各个环节&#xff0c;实现了生产流程的可视化监控。管理人员可…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

反射获取方法和属性

Java反射获取方法 在Java中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&#xff0c;允许程序在运行时访问和操作类的内部属性和方法。通过反射&#xff0c;可以动态地创建对象、调用方法、改变属性值&#xff0c;这在很多Java框架中如Spring和Hiberna…...

微服务商城-商品微服务

数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...

JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案

JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停​​ 1. ​​安全点(Safepoint)阻塞​​ ​​现象​​:JVM暂停但无GC日志,日志显示No GCs detected。​​原因​​:JVM等待所有线程进入安全点(如…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

C#学习第29天:表达式树(Expression Trees)

目录 什么是表达式树&#xff1f; 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持&#xff1a; 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

GitHub 趋势日报 (2025年06月06日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...