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 的本质一样,都是进行依赖控制。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

PROTEUS、KEIL、AD安装包和PROTEUS使用说明

仿真推荐使用PROTEUS8.15版本&#xff0c;代码推荐使用KEIL5 C51版本&#xff0c;原理图推荐使用AD20版本&#xff0c;如果版本不对会存在打不开&#xff0c;报错等问题。 PROTRUS8.15安装链接 Proteus 8.15安装教程 keil5 C51安装链接 Keil uvision5 MDKv534安装教程 AD2…

安谋科技发布全新自研“玲珑”多媒体处理器

当前&#xff0c;受视频直播、AR/VR、智驾智舱等新兴应用场景和使用人群的飞速增长&#xff0c;视频编解码及显示处理领域呈现出旺盛需求&#xff0c;进而带动了下游设备数量不断攀升。以智能汽车为例&#xff0c;根据盖世汽车研究院的产业报告显示&#xff0c;预计2025年国内车…

Redis——分布式锁

基本原理 分布式锁&#xff1a;满足分布式系统或集群模式下多进程可见并且互斥的锁 为什么要有分布式锁&#xff1f; 在只有一台服务器提供服务的情况下&#xff0c;乐观锁和悲观锁足以解决线程并发导致的问题。但是企业开发中避免不了需要部署多台服务器&#xff0c;即采用…

【医疗大数据】医疗保健领域的大数据管理:采用挑战和影响

选自期刊**《International Journal of Information Management》**&#xff08;IF:21.0) 医疗保健领域的大数据管理&#xff1a;采用挑战和影响 1、研究背景 本研究的目标是调查阻止医疗机构实施成功大数据系统的组织障碍&#xff0c;识别和评估这些障碍&#xff0c;并为管理…

【计算机网络 - 基础问题】每日 3 题(十六)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏&…

JavaScript发送邮件:实现前端触发的教程?

JavaScript发送邮件的方式&#xff1f;怎么使用JavaScript发信&#xff1f; 无论是用户反馈、联系表单还是自动通知&#xff0c;前端触发的邮件发送功能都能极大地提升用户体验。AokSend将详细介绍如何通过JavaScript发送邮件&#xff0c;实现前端触发的邮件发送功能。 JavaS…

JavaEE:网络编程(UDP)

文章目录 UDPUDP的特点UDP协议端格式校验和前置知识校验和具体是如何工作的? UDP UDP的特点 UDP传输的过程类似于寄信. 无连接: 知道对端的IP和端口号就直接进行传输,不需要建立连接.不可靠: 没有确认机制,没有重传机制,如果因为网络故障导致该段无法到达对方,UDP协议也不会…

社交电商中“信任”基础与“链动 2+1 模式 O2O 商城小程序”的价值探索

摘要&#xff1a;本文深入探讨了在基于社交的商业模式中&#xff0c;“信任”作为重要基础条件的关键作用。详细分析了在产品同质化日益严重的当下&#xff0c;人与人之间口口相传的宣传方式优势。同时&#xff0c;全面引入“链动 21 模式 O2O 商城小程序”&#xff0c;深入阐述…

【python对遥感数据进行数据清洗和归一化处理,以高分6号卫星(WFV)数据为例】

python对遥感数据进行数据清洗和归一化处理&#xff0c;以高分6号卫星&#xff08;WFV&#xff09;数据为例 处理遥感数据&#xff0c;如高分6号卫星&#xff08;GF-6&#xff09;的宽视场成像仪&#xff08;WFV&#xff09;数据&#xff0c;通常涉及数据读取、数据清洗&…

软硬件项目运维方案(Doc原件完整版套用)

1 系统的服务内容 1.1 服务目标 1.2 信息资产统计服务 1.3 网络、安全系统运维服务 1.4 主机、存储系统运维服务 1.5 数据库系统运维服务 1.6 中间件运维服务 2 运维服务流程 3 服务管理制度规范 3.1 服务时间 3.2 行为规范 3.3 现场服务支持规范 3.4 问题记录规范…

领夹麦克风什么牌子好,无线麦克风哪个好,领夹麦克风品牌排行榜

无线领夹麦克风已成为现代生活中不可或缺的沟通工具&#xff0c;但市场中仍存在一些未被广泛认知的陷阱&#xff0c;例如&#xff1a;部分产品因设计缺陷&#xff0c;如电池寿命短、抗风噪能力弱&#xff0c;影响了用户体验。作为一名音频设备测评师&#xff0c;我将揭示无线领…

原生+jquery写自动消失的提示框

<!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width, initial-scale1.0"> <title>自动消失消息提示</title> <style>/…

2.4 卷积2

2.4.2 复正弦波与整体方案 在2.3节中&#xff0c;我们提出了关于复正弦输入的频域输出及其意义的两个问题。为了研究这些问题&#xff0c;我们让一个具有真实脉冲响应 h [ n ] h[n] h[n]&#xff08;即 h Q [ n ] 0 h_Q[n] 0 hQ​[n]0&#xff09;的LTI系统通过输入复正弦…

将本地离线Jar包上传到Maven远程私库上,供项目编译使用

背景 因项目对接需求&#xff0c;需对接第三方Jar(海康人脸识别服务网关API)&#xff0c;在项目集成时&#xff0c;处于本地编译、远程持续构建的需要将离线Jar推送到远程Maven仓库。 实施步骤 进入到离线Jar包同文件夹下 配置Maven配置文件中远程账户信息 需要在Idea配置的…

字节跳动算法岗面试亲历:高效流程大公开,通关诀窍全掌握

最近这一两周看到不少互联网公司都已经开始秋招提前批了。 不同以往的是&#xff0c;当前职场环境已不再是那个双向奔赴时代了。求职者在变多&#xff0c;HC 在变少&#xff0c;岗位要求还更高了。 个人情况 985 本硕项目一个论文一篇无实习经历 时间节点 7.2 技术面一面 …

[通信原理]确知信号1:傅里叶分析

傅里叶分析 周期函数可以用直流分量、正弦函数和余弦函数构成的无穷级数来表示&#xff0c;这些函数是正交的&#xff0c;意味着它们之间没有任何相关性。‌ 必须指出&#xff0c;并非任意周期信号都能进行傅里叶级数展开&#xff0c;函数需满足狄利赫里条件才能被展开。通常…

油耳用棉签还是挖耳勺?好用的无线可视挖耳勺推荐

很多小伙伴在清理耳朵时在考虑用棉签好还是挖耳勺好&#xff0c;用棉签清理的耳道很容易将棉絮残留在耳道中引起耳道感染。而普通的挖耳勺在使用过程中容易因为操作不旦弄伤到耳朵。所以在掏耳的过程中建议大家使用可视挖耳勺会更安全和精准。但也存在品牌繁杂的情况&#xff0…

Unity实现原始的发射子弹效果

1 创建一个炮塔&#xff0c;按下空格-坦克会发射一个小球2.小球会掉在地上滚下来-添加组件3 间隔几秒后自动销毁程序逻辑&#xff1a;1.在场景中创建一个炮塔\子弹拿到代码里的变量里程序逻辑&#xff1a; 2.if语句检测用户有没有按下空格程序逻辑&#xff1a; 3.在炮塔坐标的位…

UWA支持鸿蒙HarmonyOS NEXT

华为在开发者大会上&#xff0c;宣布了鸿蒙HarmonyOS NEXT将仅支持鸿蒙内核和鸿蒙系统的应用&#xff0c;不再兼容安卓应用&#xff0c;这意味着它将构建一个全新且完全独立的生态系统。 为此&#xff0c;UWA也将在最新版的UWA SDK v2.5.0中支持鸿蒙HarmonyOS NEXT&#xff0c…

出差乘坐高铁,车票如何开电子发票?

出差乘坐高铁&#xff0c;车票如何开电子发票 如果您由于公务乘坐火车/高铁&#xff0c;但事后需要打印报销发票&#xff0c;该如何操作呢&#xff1f;车票可以开电子发票吗&#xff1f; 目前火车票/高铁票没有电子发票。 高铁、火车等交通工具的票务流程涉及改签、退票等多…