【React】React18 Hooks 之memo、useCallback

目录

  • React.memo()
    • 案例1: 无依赖项,无props
    • 案例1: props比较机机制
      • (1)传递基本类型,props变化时组件重新渲染
      • (2)传递的是引用类型的prop,比较的是新值和旧值的引用
      • (3)保证引用类型稳定,使用useMemo
  • useCallback
    • 案例1:不带依赖项数组
    • 案例2:带依赖项数组
  • 好书推荐

在这里插入图片描述

useCallback官方地址
memo官方地址

React组件的默认渲染机制:

  • 只要父组件重新渲染,组件就会重新渲染。
  • 组件的自身的state发生了变化,组件就会重新渲染。

React的性能优化途径是之一就是对 组件、函数以及函数执行结果进行缓存,组件渲染时避开一些不必要的代码执行。

父组件每次重新渲染都触发子组件的重新渲染有的时候是没有必要的,即当子组件的内部数据不依赖于父组件此次的重新渲染,那么我们就没有必要去对子组件进行重新渲染。即有的组件无论如何渲染,每次的渲染结果都是相同的,很显然这种渲染是完全没有必要的。

为了减少这种组件的渲染,React提供了一个高阶函数React.memo(),可以用来缓存组件;React还提供useCallback钩子,可以缓存函数,依赖项不变的情况下,保持函数不会更新。

React.memo()

只要父组件重新渲染,React 就会重新渲染该组件。使用memo,你可以创建一个组件,只要其新 props 与旧props相同,React 就不会在其父组件重新渲染时重新渲染该组件.

用法:

memo(Component, arePropsEqual?) 

memo返回一个新的 React 组件,参数含义:

  • Component:要记忆的组件。不会memo修改此组件,而是返回一个新的记忆组件。任何有效的 React 组件(包括函数和forwardRef组件)均可接受。

  • arePropsEqual:接受两个参数的函数:组件的先前 props 及其新 props。默认情况下,React 会通过Object.is将每个 prop 与 进行比较.

案例1: 无依赖项,无props

// 1默认的渲染机制,子跟父一起渲染
// 2memo进行缓存,只用props发生变化的时候才会重新渲染(不考虑context)import { useState,memo } from "react";const MemoSon = memo(function Son(){console.log("我是子组件")return <div>this is Son</div>
})function App() {
const [count,setCount] = useState(0)return (<div className="App">{count}<button onClick={()=>setCount(count+1)}>+</button><MemoSon/></div>);
}export default App;

案例1: props比较机机制

(1)传递基本类型,props变化时组件重新渲染

传过来的props发生了变化,所以子组件更新


import { useState,memo } from "react";const MemoSon = memo(function Son({count}){console.log("我是子组件")return <div>this is Son {count}</div>
})function App() {
const [count,setCount] = useState(0)return (<div className="App">{count}<button onClick={()=>setCount(count+1)}>+</button><MemoSon count={count}/></div>);
}export default App;

下面代码props传过去的固定的基本类型的值,点击按钮子组件不更新。

import { useState,memo } from "react";const MemoSon = memo(function Son({count}){console.log("我是子组件")return <div>this is Son {count}</div>
})function App() {
const [count,setCount] = useState(0)
const num =100;return (<div className="App">{count}<button onClick={()=>setCount(count+1)}>+</button><MemoSon count={num}/></div>);
}export default App;

(2)传递的是引用类型的prop,比较的是新值和旧值的引用

点击加号按钮,App组件会重新渲染,声明的list就会有新的引用,所以子组件会重新渲染

import { useState,memo } from "react";const MemoSon = memo(function Son({list}){console.log("我是子组件")return <div>this is Son {list}</div>
})function App() {
const [count,setCount] = useState(0)
const num =100;
const list = [1,2,3];return (<div className="App">{count}<button onClick={()=>setCount(count+1)}>+</button><MemoSon list={list}/></div>);
}export default App;

(3)保证引用类型稳定,使用useMemo

使用useMemo,组件渲染过程中缓存一个值,所以在点击按钮时,App组件重新渲染,而此时list还是之前的引用,故而,子组件不会重新渲染

import { useState, memo, useMemo } from "react";const MemoSon = memo(function Son({ list }) {console.log("我是子组件")return <div>this is Son {list}</div>
})function App() {const [count, setCount] = useState(0)const num = 100;// 空数组,只在组件渲染时执行一次。const list = useMemo(() => {return [1, 2, 3]}, [])return (<div className="App">{count}<button onClick={() => setCount(count + 1)}>+</button><MemoSon list={list} /></div>);
}export default App;

useCallback

在组件的顶层调用useCallback,组件多次重新渲染的时候缓存函数。

用法:

useCallback(fn, dependencies) 

useCallback钩子接收两个参数,内联回调函数和依赖数组。它将返回该回调函数的memoized函数,只有仅在某个依赖项改变时,回调函数会更新。

案例1:不带依赖项数组

App.js中,点击“+”按钮,增加count数值,可以看到父组件打印“父组件渲染”,子组件打印“子组件重新渲染”。是因为父组件更新之后,传递给子组件的函数changeHandler也更新了,所以导致子组件的props发生变化,子组件重新渲染。其中子组件用memo包裹,memo让你在组件的 props 不变的情况下跳过重新渲染组件。

import { useState, memo, useMemo, useCallback } from "react";
const Input =  memo(function Input({onChange}){console.log("子组件重新渲染")return <input type ="text" onChange={(e)=>onChange(e.target.value)}/>
})function App() {console.log("父组件渲染")const [count, setCount] = useState(0)const changeHandler = value => console.log(value))return (<div className="App">{/* 把函数作为prop传递给子组件 */}<Input onChange = {changeHandler} />{count}<button onClick={()=>setCount(count+1)}>+</button></div>);
}
export default App;  

在这里插入图片描述
其实可以看到子组件是没有必要重新渲染的,并且增加页面渲染的时间,逻辑复杂可能会卡顿。

使用useCallback修改上面的代码
点击加号按钮后,可以看到只有父组件打印了“父组件渲染”,子组件并没有重新渲染。父组件使用useCallback缓存了changeHandler,传递给子组件的函数changeHandler不会发生变化,还是之前的引用,所以子组件的props不会发生变化,子组件不会重新渲染。

  const changeHandler = useCallback( value => console.log(value),[])

在这里插入图片描述

案例2:带依赖项数组

这里只是举个例子,changeHandler函数依赖于count,发现点击加号按钮时,父组件,子组件均重新渲染,且在input输入框中输入数据,打印出count的值。

import { useState, memo, useMemo, useCallback } from "react";import MegaBoost from "./MegaBoost";
const Input = memo(function Input({onChange}){console.log("子组件重新渲染")return <input type ="text" onChange={(e)=>onChange(e.target.value)}/>
}) function App() {console.log("父组件渲染")const [count, setCount] = useState(0)const changeHandler = useCallback( value=> console.log(count,'value') ,[count])return (   <div className="App">{/* 把函数作为prop传递给子组件 */}<Input onChange = {changeHandler} />{/* <MegaBoost handleClick={changeHandler} /> */}<button onClick={()=>setCount(count+1)}>+</button></div>);
}export default App;  

在这里插入图片描述

好书推荐

Vue.js 3.x+Express全栈开发:从0到1打造商城项目

《Vue.js 3.x+Express全栈开发 : 从0到1打造商城项目》是一本详尽的全栈开发教程,旨在通过Vue.js和Express框架引导读者从零开始构建一个完整的电商项目。内容覆盖电商项目的基本结构,以及Vue.js和Express的核心概念与架构;深入讲解Vue.js开发生态中的关键模块,包括网络请求、UI组件、路由管理和状态管理等;探讨Express框架的常用组件,如处理加密数据的中间件和与MySQL数据库交互的插件;最后指导读者打造一个完整的电商项目。在用户端,实现注册登录、商品浏览、购物车等功能;在服务端,完成用户验证、商品维护、订单处理等任务;在后台管理端,进行商品信息、订单数据等的管理与统计分析。通过阅读《Vue.js 3.x+Express全栈开发 : 从0到1打造商城项目》,读者能够掌握Vue.js和Express全栈开发技术,并独立完成电商项目的搭建与开发。《Vue.js 3.x+Express全栈开发 : 从0到1打造商城项目》还提供了完整的项目源码、代码导读手册以及长达30小时的教学视频,可大幅提升学习效率。
在这里插入图片描述

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

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

相关文章

React的usestate设置了值后马上打印获取不到最新值

我们在使用usestate有时候设置了值后&#xff0c;我们想要更新一些值&#xff0c;这时候&#xff0c;我们要想要马上获取这个值去做一些处理&#xff0c;发现获取不到&#xff0c;这是为什么呢&#xff1f; 效果如下&#xff1a; 1、原因如下 在React中,当你使用useState钩子…

【STM32 HAL库】I2S的使用

使用CubeIDE实现I2S发数据 1、配置I2S 我们的有效数据是32位的&#xff0c;使用飞利浦格式。 2、配置DMA **这里需要注意&#xff1a;**i2s的DR寄存器是16位的&#xff0c;如果需要发送32位的数据&#xff0c;是需要写两次DR寄存器的&#xff0c;所以DMA的外设数据宽度设置16…

一文详解数据仓库、数据湖、湖仓一体和数据网格

随着数字化时代的到来&#xff0c;近几年数据领域的新技术概念不断涌现&#xff0c;数据湖、湖仓一体、流批一体、存算一体、数据编织抑或数据网格等新概念层出不穷&#xff0c;成为数据管理领域的新宠。本文将探讨主要探讨数据仓库、数据湖、湖仓一体以及数据网格的优势和局限…

【第三章】Bug篇

文章目录 软件测试的生命周期BUG分级如何描述BUGBUG分级BUG的生命周期 在工作中与开发人员产生争执怎么办 软件测试的生命周期 软件测试贯穿于软件的整个生命周期&#xff0c;具体的软件开发到维护的每一个阶段都需要有测试步骤去保证产品质量。下面简要分析软件测试的具体流程…

变频压缩机变频调节特点

变频压缩机以其能耗低、工况适应性强等优点让其得到更多的应用&#xff0c;但它的特点和注意事项&#xff0c;也不能忽视&#xff0c;以免产生相反的效果。 一、变频调节的特点 1、按照额定负荷设计的制冷空调系统在压缩机低转速运行时&#xff0c;压缩机的质量流量减少&#…

Unity格斗游戏,两个角色之间互相锁定对方,做圆周运动

1&#xff0c;灵感来源 今天手头的工作忙完了&#xff0c;就等着服务器那边完活&#xff0c;于是开始研究同步问题。 正好想到之前想做的&#xff0c;两个小人对线PK&#xff0c;便有了这篇文章。 2&#xff0c;要实现的效果 如图所示&#xff0c;两个小人可以互相锁定&…

Python中发送邮件的艺术:普通邮件、PDF附件与Markdown附件

用的是qq邮箱,具体获取smtp的password可以看这个文章 获取密码 Python中发送邮件的艺术:普通邮件、PDF附件与Markdown附件 在今天的博客中,我们将探讨如何使用Python的smtplib库来发送电子邮件,包括发送普通文本邮件、携带PDF文件的邮件和附带Markdown文件的邮件。这些功能…

力扣2296.设计一个文本编辑器

力扣2296.设计一个文本编辑器 对顶栈 将光标看作左右栈的分隔添加元素&#xff1a;往左栈添加元素删除元素&#xff1a;从左栈删除元素光标左(右)移&#xff1a;左(右)栈元素加到右(左)栈 class TextEditor {string left,right;public:TextEditor() {}void addText(string…

linux下JDK的安装

前言&#xff1a; 安装部署java开发的代码都需要java环境&#xff0c;这里记录下linux下JDK的安装过程&#xff0c;仅供学习参考。 JDK的下载 下载地址&#xff1a;https://www.oracle.com/java/technologies/downloads 选择和操作系统匹配的版本进行下载 查看操作系统&…

乐尚代驾二乘客登录与司机登录

乘客登录 需求说明 openid是小程序端微信的唯一标识 数据库表 表中存在openid就不是第一次登录&#xff0c;否则就是第一次登录 登录流程时序 如果是第一次登录&#xff0c;注册之后也是要返回token的code就是单纯什么参数都没有&#xff0c;直接调用微信接口服务的wx.logi…

Games101学习笔记 Lecture22 Animation(cont.)

Lecture22 Animation(cont. 一、单个粒子模拟Ordinary Differential Equation ODE 常微分方程ODE求解方法——欧拉方法解决不稳定中点法改进欧拉方法自适应步长隐式欧拉方法 二、流体模拟基于位置的方法物质点方法 一、单个粒子模拟 想模拟粒子在场中的运动 Ordinary Differe…

使用OpenCV寻找图像中的轮廓

引言 OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源的计算机视觉和机器学习软件库。它提供了大量的视觉处理功能&#xff0c;包括图像和视频捕获、特征检测与匹配、图像变换、图像分割、颜色空间转换等。在图像处理中&#xff0c;寻找图像中的…

Docker容器下安装Matlab,无需挂载

Matlab的安装需要这些文件 传入ubuntu后&#xff0c;改过相关的文件权限后&#xff0c;发现还是无法挂载 这有可能是docker的安全管理策略导致容器不能挂载&#xff0c;因此采用不挂载形式&#xff0c;直接解压的方式安装Matlab 1.将iso改成zip&#xff0c;并解压 2.解压rar文件…

MimicMotion-腾讯开源视频生成框架

腾讯宣布开源可控视频生成框架 MimicMotion&#xff0c;该框架可以通过提供参考人像及由骨骼序列表示的动作&#xff0c;来产生平滑的高质量人体动作视频 MimicMotion 具有以下几个亮点&#xff1a; 首先&#xff0c;通过引入了置信度感知的姿态引导信号&#xff0c;大幅提升了…

Ubuntu20.04从零开搭PX4MavrosGazebo环境并测试

仅仅是个人搭建记录 参考链接&#xff1a; https://zhuanlan.zhihu.com/p/686439920 仿真平台基础配置&#xff08;对应PX4 1.13版&#xff09; 语雀 mkdir -p ~/tzb/catkin_ws/src mkdir -p ~/tzb/catkin_ws/scripts cd catkin_ws && catkin init catkin build cd…

Re-labeling ImageNet(CVPR 2021, Naver)

paper&#xff1a;Re-labeling ImageNet: from Single to Multi-Labels, from Global to Localized Labels official implementation&#xff1a;GitHub - naver-ai/relabel_imagenet 背景 ImageNet 数据集是现代计算机视觉领域的重要基准&#xff0c;广泛用于图像分类模型的…

中国社科大与英国斯特灵大学合作办学双证创新与领导力管理学博士

中国社科大与英国斯特灵大学合作办学双证创新与领导力管理学博士&#xff0c;2024级火热报名申请中&#xff0c;不想脱产的&#xff0c;不想发表论文的&#xff0c;不想长时间出国的&#xff0c;想短期获取博士学位的&#xff0c;想留服认证的&#xff0c;把握短暂机会啦&#…

网络故障处理及分析工具:Wireshark和Tcpdump集成

Wireshark 是一款免费的开源数据包嗅探器和网络协议分析器&#xff0c;已成为网络故障排除、分析和安全&#xff08;双向&#xff09;中不可或缺的工具。 本文深入探讨了充分利用 Wireshark 的功能、用途和实用技巧。 无论您是开发人员、安全专家&#xff0c;还是只是对网络操…

前端面试题(JS篇五)

一、同步与异步的区别 同步指的是当一个进程在执行某一个请求的时候&#xff0c;如果这个请求需要等待一段时间才能返回&#xff0c;那么这个进程会一直等待下去&#xff0c;直到这个消息返回之后才会继续执行。 指的是当一个进程在执行某一个请求的时候&#xff0c;如果这个请…

PSINS工具箱函数介绍——r2d

介绍工具箱里面r2d这个小函数的作用。 程序源码 function deg r2d(rad) % Convert angle unit from radian to degree % % Prototype: deg r2d(rad) % Input: rad - angle in radian(s) % Output: deg - angle in degree(s) % % See also r2dm, r2dms, d2r, dm2r, dms2r% …