【React】React18 Hooks 之memo、useCallback

news2024/12/24 18:04:27

目录

  • 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://www.coloradmin.cn/o/1933503.html

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

相关文章

pyinstall 打包基于PyQt5和PaddleOCR的项目为.exe

简介&#xff1a; 最近做了一个小项目&#xff0c;是基于PyQt5和PaddleOCR的。需要将其打包为.exe&#xff0c;然后打包过程中遇到了很多问题&#xff0c;也看了很多教程&#xff0c;方法千奇百怪的&#xff0c;最后也是一步一步给试出来了。记录一下&#xff0c;防止以后忘记…

【2024年“数据要素×”大赛宁夏分赛】赛程制度

“数据要素”大赛宁夏分赛怎么报名&#xff1f;看这里 官方网站&#xff1a;https://nxsjysds.sznxgs.com/ 赛程制度 &#xff08;一&#xff09;启动报名&#xff08;7月16日-8月10日&#xff09;举办启动仪式&#xff0c;组织线上和线下推广工作&#xff0c;动员参赛队伍报…

vue3 vxe-grid修改currentPage,查询数据的时候,从第一页开始查询

1、当我们设置好VxeGrid.Options进行数据查询的时候,下面是可能的设置&#xff1a; const gridOptions reactive<BasicTableProps>({id: UserTable,showHeaderOverflow: false,showOverflow: true,keepSource: true,columns: userColumns,size: small,pagerConfig: {cur…

Python求均值,方差,标准差

参考链接&#xff1a;变异系数&#xff08;Coefficient of Variation,COV&#xff09;和协方差&#xff08;Covariance, Cov&#xff09;-CSDN博客 参考链接&#xff1a;pandas中std和numpy的np.std区别_numpy pandas std-CSDN博客 在计算蛋白质谱数据中的每个蛋白对应的变异…

【Java面向对象】多态

文章目录 1.动态绑定2.对象转换和 instanceof 操作符稍作总结3.Object 类的 equals 方法4.ArrayList 类5.继承体系中的权限问题6.final 1.动态绑定 多态意味着父类型的变量可以引用子类型的对象。 方法可以在沿着继承链的多个类中实现。JVM 决定运行时调用哪个方法。 一个变量…

新手小白攻略:如何用AI工具搭建个人知识库

个人知识库是指个人通过积累和整理&#xff0c;将各种领域的知识、经验和技能进行分类、归纳和存储的系统化工具或平台。 随着信息技术的飞速发展和知识经济的兴起&#xff0c;个人知识库不仅成为个人学习、成长和创新的基石&#xff0c;也是适应快速变化社会、提升竞争力的关…

python--实验 11 模块

目录 知识点 模块基础 模块使用方式 自定义模块示例 模块的有条件执行 Python包结构 定义和导入包 常用第三方库及安装 实例代码 第三方库自动安装脚本 Python标准库介绍 PyInstaller 小结 实验 1.(基础题)制作文本进度条。 2.(基础题) 蒙特卡罗方法计算圆周率…

nginx全局块的user指令

文章目录 1、user指令1.1、进入nginx解压的目录1.2、./configure --help1.3、工作进程默认是nobody 2、user指令的使用步骤:2.1、设置一个用户信息"www"2.2、 创建一个用户2.3、./nginx -s reload2.4、创建/root/html/index.html页面&#xff0c;添加如下内容2.5、修…

住宅IP解析:动态住宅IP和静态住宅IP区别详解

在互联网连接的世界中&#xff0c;IP地址是我们识别和访问网络资源的关键。住宅IP地址&#xff0c;特别是动态住宅IP和静态住宅IP&#xff0c;是两种不同类型的IP分配方式&#xff0c;它们在使用和功能上存在显著差异。 1. IP地址的稳定性 动态住宅IP&#xff1a;这种IP地址是…

昇思25天学习打卡营第14天|munger85

基于MindNLPMusicGen生成自己的个性化音乐 这个所谓的个性化的音乐就是指你输入一段文字它会根据这个文字输出一段音乐这个音乐是贴近于那段文字的所以叫做文生成音乐&#xff0c; 如果网络正常的话就可以直接从下载这个模型。 那么音乐生成的有两种方式呢有两种方式&#xff…

layui 让table里的下拉框不被遮挡

记录&#xff1a;layui 让table里的下拉框不被遮挡 /* 这个是让table里的下拉框不被遮挡 */ .goods_table .layui-select-title,.goods_table .layui-select-title input{line-height: 28px;height: 28px; }.goods_table .layui-table-cell {overflow: visible !important; }.…

[C++初阶]list的模拟实现

一、对于list的源码的部分分析 1.分析构造函数 首先&#xff0c;我们一开始最先看到的就是这个结点的结构体&#xff0c;在这里我们可以注意到这是一个双向链表。有一个前驱指针&#xff0c;一个后继指针。然后在有一个存储数据的空间 其次它的迭代器是一个自定义类型&#x…

【Python游戏】编程开发贪吃蛇游戏(第一期)

本文收录于 《一起学Python趣味编程》专栏&#xff0c;从零基础开始&#xff0c;分享一些Python编程知识&#xff0c;欢迎关注&#xff0c;谢谢&#xff01; 文章目录 一、前言二、贪吃蛇游戏开发简介2.1 贪吃蛇游戏规则2.2 贪吃蛇游戏开发步骤 三、贪吃蛇游戏开发实战四、总结…

13 个最受欢迎的技术写作工具

13 个最受欢迎的技术写作工具 在我的职业生涯中&#xff0c;我作为技术作家工作了大约 10 年&#xff0c;根据需要使用了各种文档工具。作为技术作家&#xff0c;主要工作职责是提供正确的内容。 使用正确的技术写作工具可以使技术作家的生活变得轻松。有多种工具可用于不同的…

【Vue】Vue3 安装 Tailwind CSS 入门

初始化 Vue 3 项目 npm install -g vue/cli vue create my-project安装 Tailwind CSS 进入你的项目目录&#xff0c;然后安装 Tailwind CSS 和其依赖项&#xff1a; npm install -D tailwindcss postcss autoprefixer配置 PostCSS Tailwind CSS 需要通过 PostCSS 进行处理。…

Linux发行版CentOS 8 利用Docker安装应用

目录 一、什么是Docker&#xff1f; 主要功能&#xff1a; 二、安装Docker 1.安装yum配置工具 2.配置docker的yum源 3.安装 4.测试 5.启动&#xff0c;关闭&#xff0c;开机自启动 三、卸载Docker 1.停止服务 2.卸载 3.删除文件 四、Docker配置镜像源 1.在etc下创建docker…

【大模型时代的PDF解析工具】

去年&#xff08;2023年&#xff09;是大模型爆发元年。但是大模型具有两个缺点&#xff1a;缺失私有领域知识和幻觉。缺失私有领域知识是指大模型训练时并没有企业私有数据/知识&#xff0c;所以无法正确回答相关问题。并且在这种情况下&#xff0c;大模型会一本正经地胡说八道…

JavaEE--JavaWeb服务器的安装配置(Tomcat服务器安装配置)

前言: 本文介绍了 Java Web 服务器 Tomcat 的安装配置&#xff0c;并详细说明了如何在 IntelliJ IDEA 中配置服务器&#xff0c;创建 JavaEE 项目&#xff0c;并发布文章。文章首先解释了前端程序如何访问后端程序以及 Web 服务器的概念&#xff0c;然后详细介绍了安装 Tomcat…

VirtualBox虚拟机与主机互传文件的方法

建立共享文件夹 1.点击设置&#xff0c;点击共享文件夹&#xff0c;添加共享文件夹路径&#xff0c;保存 2.启动虚拟机&#xff0c;点击设备&#xff0c;点击安装增强功能&#xff0c;界面会出现一个光碟图标&#xff0c;点击光碟图标 3.打开光碟图标&#xff0c;出现一个目…

Vue3渐变文字(GradientText)

效果如下图&#xff1a;在线预览 APIs GradientText 参数说明类型默认值必传gradient文字渐变色参数string | Gradientundefinedfalsesize文字大小&#xff0c;不指定单位时&#xff0c;默认单位 pxnumber | string14falsetype渐变文字的类型‘primary’ | ‘info’ | ‘succ…