usecallback()与usememo()

简单的说

都是用来监听数据变化 来进行控制渲染、减少不必要的渲染 、优化性能
usecallback()是用来监听数据变化从而调用方法
usememo()是用来监听数据变化从而改变数据 使用return返回变化的数据 当然return 也可以返回方法 所以usememo()可以代替usecallback()

下面详解

useCallback:缓存回调函数

在 React 函数组件中,每一次 UI 的变化,都是通过重新执行整个函数来完成的,这和传统的 Class 组件有很大区别:函数组件中并没有一个直接的方式在多次渲染之间维持一个状态。 比如下面的代码中,我们在加号按钮上定义了一个事件处理函数,用来让计数器加 1。但是因为定义是在函数组件内部,因此在多次渲染之间,是无法重用 handleIncrement 这个函数的,而是每次都需要创建一个新的:

function Counter() {const [count, setCount] = useState(0);const handleIncrement = () => setCount(count + 1);// ...return <button onClick={handleIncrement}>+</button>
}

你不妨思考下这个过程。每次组件状态发生变化的时候,函数组件实际上都会重新执行一遍。在每次执行的时候,实际上都会创建一个新的事件处理函数 handleIncrement。
这个事件处理函数中呢,包含了 count 这个变量的闭包,以确保每次能够得到正确的结果。 这也意味着,即使 count 没有发生变化,但是函数组件因为其它状态发生变化而重新渲染时,这种写法也会每次创建一个新的函数
创建一个新的事件处理函数,虽然不影响结果的正确性,但其实是没必要的。因为这样做不仅增加了系统的开销,更重要的是:每次创建新函数的方式会让接收事件处理函数的组件,需要重新渲染。
比如这个例子中的 button 组件,接收了 handleIncrement ,并作为一个属性。如果每次都是一个新的,那么这个 React 就会认为这个组件的 props 发生了变化,从而必须重新渲染。因此,我们需要做到的是:**只有当 count 发生变化时,我们才需要重新定一个回调函数。**而这正是 useCallback 这个 Hook 的作用。

import React, { useState, useCallback } from 'react';
function Counter() {const [count, setCount] = useState(0);const handleIncrement = useCallback(() => setCount(count + 1),[count], // 只有当 count 发生变化时,才会重新创建回调函数);// ...return <button onClick={handleIncrement}>+</button>
}

在这里,我们把 count 这个 state ,作为一个依赖传递给 useCallback。这样,只有 count 发生变化的时候,才需要重新创建一个回调函数,这样就保证了组件不会创建重复的回调函数。而接收这个回调函数作为属性的组件,也不会频繁地需要重新渲染。

useMemo:缓存计算的结果

如果某个数据是通过其它数据计算得到的,那么只有当用到的数据,也就是依赖的数据发生变化的时候,才应该需要重新计算。
举个例子,对于一个显示用户信息的列表,现在需要对用户名进行搜索,且 UI 上需要根据搜索关键字显示过滤后的用户,那么这样一个功能需要有两个状态:
1.用户列表数据本身:来自某个请求。
2.搜索关键字:用户在搜索框输入的数据。
无论是两个数据中的哪一个发生变化,都需要过滤用户列表以获得需要展示的数据。那么如果不使用 useMemo 的话,就需要用这样的代码实现:

import React, { useState, useEffect } from "react";export default function SearchUserList() {const [users, setUsers] = useState(null);const [searchKey, setSearchKey] = useState("");useEffect(() => {const doFetch = async () => {// 组件首次加载时发请求获取用户数据const res = await fetch("https://reqres.in/api/users/");setUsers(await res.json());};doFetch();}, []);let usersToShow = null;if (users) {// 无论组件为何刷新,这里一定会对数组做一次过滤的操作usersToShow = users.data.filter((user) =>user.first_name.includes(searchKey),);}return (<div><inputtype="text"value={searchKey}onChange={(evt) => setSearchKey(evt.target.value)}/><ul>{usersToShow &&usersToShow.length > 0 &&usersToShow.map((user) => {return <li key={user.id}>{user.first_name}</li>;})}</ul></div>);
}

在这个例子中,无论组件为何要进行一次重新渲染,实际上都需要进行一次过滤的操作。但其实你只需要在 users 或者 searchKey 这两个状态中的某一个发生变化时,重新计算获得需要展示的数据就行了。那么,这个时候,我们就可以用 useMemo 这个 Hook 来实现这个逻辑,缓存计算的结果
//…
// 使用 userMemo 缓存计算的结果

const usersToShow = useMemo(() => {if (!users) return null;return users.data.filter((user) => {return user.first_name.includes(searchKey));}}, [users, searchKey]);
//...

可以看到,通过 useMemo 这个 Hook,可以避免在用到的数据没发生变化时进行的重复计算。虽然例子展示的是一个很简单的场景,但如果是一个复杂的计算,那么对于提升性能会有很大的帮助。
这也是 userMemo 的一大好处:避免重复计算。 除了避免重复计算之外,useMemo 还有一个很重要的好处:避免子组件的重复渲染。比如在例子中的 usersToShow 这个变量,如果每次都需要重新计算来得到,那么对于 UserList 这个组件而言,就会每次都需要刷新,因为它将 usersToShow 作为了一个属性。而一旦能够缓存上次的结果,就和 useCallback 的场景一样,可以避免很多不必要的组件刷新。

这个时候,如果我们结合 useMemo 和 useCallback 这两个 Hooks 一起看,会发现一个有趣的特性,那就是 useCallback 的功能其实是可以用 useMemo 来实现的。比如下面的代码就是利用 useMemo 实现了 useCallback 的功能

 const myEventHandler = useMemo(() => {// 返回一个函数作为缓存结果return () => {// 在这里进行事件处理}}, [dep1, dep2]);

理解了这一点,相信你一下子会对这两个 Hooks 的机制有更进一步的认识,也就不用死记硬背两个 API 都是干嘛的了,因为从本质上来说,它们只是做了同一件事情:建立了一个绑定某个结果到依赖数据的关系。只有当依赖变了,这个结果才需要被重新得到。

深入讨论usecallback()

开发过程中我遇到了

const toggleTheme = useCallback(() => 
{ 
setTheme((theme) =>(theme === "light" ? "dark" : "light")); 
}, []);

疑问?为什么没有依赖项 不需要依赖theme 获取最新的theme的值么
答:
useCallback 的依赖项数组是用于确定何时重新计算缓存的函数的。如果依赖项数组中有任何值发生变化,那么函数将被重新创建。

然而,对于 toggleTheme 函数,你并不需要在依赖项数组中包含 theme。这是因为你是在函数内部直接读取 theme 的最新值,而不是依赖于外部的 theme 变量。这是 setTheme 函数的一个特性:当你传递一个函数给 setTheme,React 会将 当前的 theme 状态值作为那个函数的参数

所以,即使 theme 值在多次渲染之间发生变化,toggleTheme 函数总是能读取到最新的 theme 值,因此不需要在依赖项数组中包含 theme。

这种模式在你想要根据当前状态值更新状态时是非常有用的,因为它可以确保你总是使用最新的状态值,而不是在闭包中缓存的旧值。

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

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

相关文章

常见的编码技术简介

常见的编码技术简介 文章目录 常见的编码技术简介1. 字符编码1.1 ASCII1.2 Unicode 2. 数据传输编码2.1 Base系列编码2.1.1 Base642.1.2 Base162.1.3 Base322.1.4 Base852.1.5 其他Base编码 2.2 URL编码2.3 JSON2.4 XML2.5 Protobuf (Protocol Buffers) 1. 字符编码 1.1 ASCII…

AI是在帮助开发者还是取代他们?——探讨AI在软件开发中的角色与未来

引言 随着人工智能技术的迅猛发展&#xff0c;AI工具在软件开发中的应用越来越广泛。有人认为AI可以显著提升开发者的效率&#xff0c;而也有人担心AI会取代开发者的工作。本文将从三个方面探讨AI在软件开发中的角色&#xff1a;AI工具现状、AI对开发者的影响以及AI开发的未来…

学习springAOP

第三章 Spring AOP 第一节 AOP 简介 1. 概念 AOP全称为Aspect Oriented Programming&#xff0c;表示面向切面编程。何为切面呢&#xff1f; 由此可以得出&#xff0c;切面是一种将那些与业务无关&#xff0c;但业务模块都需要使用的功能封装起来的技术。这样便于减少系统的…

昇思25天学习打卡营第4天|应用实践

昇思25天学习打卡营第4天 文章目录 昇思25天学习打卡营第4天基于 MindSpore 实现 BERT 对话情绪识别模型简介环境配置数据集数据加载和数据预处理input_idsattention_mask 模型构建模型验证模型推理自定义推理数据集 打卡记录 基于 MindSpore 实现 BERT 对话情绪识别 模型简介…

奥比中光astra_pro相机使用记录

一、信息获取 1、官网 用于了解产品信息 http://www.orbbec.com.cn/sys/37.html 2、开发者社区 咨询问题下载开发部https://developer.orbbec.com.cn/ 二 、windowvs19 1、相机型号 orbbec_astro_pro 根据对应的型号找到需要的包工具 踩坑1&#xff0c;因为这个相机型号…

第20章 Mac+VSCode配置C++环境

1. 下载VSCode VSCode下载地址在mac终端里输入xcode- select --install命令&#xff0c;根据提示安装xcode工具。 2. 安装插件&#xff08;4个&#xff09; 打开VScode&#xff0c;点击应用右侧菜单栏 C/C&#xff08;必装&#xff09; Code Runner&#xff08;必装&#xf…

UCOS-III 任务调度与就绪列表管理

01. 就绪优先级位图 在实时操作系统中&#xff0c;任务调度的效率至关重要。UCOS-III通过就绪优先级位图来快速查找最高优先级的就绪任务&#xff0c;从而实现高效调度。就绪优先级位图是一个按位表示的结构&#xff0c;每个位代表一个优先级&#xff0c;当某个优先级上有任务就…

高效管理 TensorFlow 2 GPU 显存的实用指南

前言 在使用 TensorFlow 2 进行训练或预测时&#xff0c;合理管理 GPU 显存至关重要。未能有效管理和释放 GPU 显存可能导致显存泄漏&#xff0c;进而影响后续的计算任务。在这篇文章中&#xff0c;我们将探讨几种方法来有效释放 GPU 显存&#xff0c;包括常规方法和强制终止任…

【FFmpeg】avcodec_open2函数

目录 1. avcodec_open21.1 编解码器的预初始化&#xff08;ff_encode_preinit & ff_decode_preinit&#xff09;1.2 编解码器的初始化&#xff08;init&#xff09;1.3 释放编解码器&#xff08;ff_codec_close&#xff09; FFmpeg相关记录&#xff1a; 示例工程&#xff…

Windows编程之多线程事件对象(Event Object)用法详解

目录 一、前言 二、基础用法 三、API详解 1.创建事件对象 2控制事件状态 3.等待事件对象&#xff1a; 四、实战案例 1.案例描述 2.代码设计 3.总设计代码 4.运行结果 一、前言 事件对象&#xff08;Event Object&#xff09;是我们在大型项目中&#xff0c;进行多线…

竞赛选题 医学大数据分析 - 心血管疾病分析

文章目录 1 前言1 课题背景2 数据处理3 数据可视化4 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于大数据的心血管疾病分析 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9…

AI绘画Stable Diffusion 解锁精美壁纸创作:利用SD与LLM定制你的专属壁纸,AI副业变现指南!

大家好&#xff0c;我是画画的小强 今天给大家分享一下用AI绘画Stable Diffusion 制作精美手机壁纸&#xff0c;这也可能是当前最快AIGC变现的一种途径。虽然本文的主题为手机壁纸&#xff0c;当调整不同的比例的分辨率宽高比例&#xff0c;就可以直接复用到手机、电脑和平板、…

旋转和镜像的关系

旋转矩阵行列式与 在E(3)三维空间中&#xff0c;旋转矩阵的行列式可以用来判断该旋转是否包含镜像变换。 行列式为正&#xff1a; 表示纯旋转&#xff0c;不包含镜像。 旋转矩阵保持向量的长度和角度不变&#xff0c;只是改变向量的方向。 行列式为负&#xff1a; 表示旋转…

机器学习原理之 -- 支持向量机分类:由来及原理详解

支持向量机&#xff08;Support Vector Machine, SVM&#xff09;是统计学习理论的一个重要成果&#xff0c;广泛应用于分类和回归问题。SVM以其高效的分类性能和良好的泛化能力在机器学习领域中占据重要地位。本文将详细介绍支持向量机的由来、基本原理、构建过程及其优缺点。…

LVS负载均衡群集部署之——DR模式的介绍及搭建步骤

一、LVS-DR集群介绍1.1 LVS-DR 工作原理1.2 数据包流向分析1.3 LVS-DR 模式的特点1.4 LVS-DR中的ARP问题1.4.1 问题一1.4.2 问题二二、构建LVS-DR集群2.1 构建LVS-DR集群的步骤&#xff08;理论&#xff09;1.配置负载调度器&#xff08;192.168.80.30&#xff09;&#xff08;…

5分钟教你用AI把老照片动起来,别再去花49块9的冤枉钱了

文章目录 需要的工具 最近&#xff0c;AI视频在各大平台上&#xff0c;又火了。 只是火的形式&#xff0c;变成了将老照片动起来&#xff0c;打情感牌&#xff0c;或者做很多经典电视剧的再整活。 直接把可灵的生成时间&#xff0c;从以前的4分钟&#xff0c;生生的干成了20分钟…

鸿蒙应用笔记

安装就跳过了&#xff0c;一直点点就可以了 配置跳过&#xff0c;就自动下了点东西。 鸿蒙那个下载要12g个内存&#xff0c;大的有点吓人。 里面跟idea没区别 模拟器或者真机运行 真机要鸿蒙4.0&#xff0c;就可以实机调试 直接在手机里面跑&#xff0c;这个牛逼&#xf…

国标GB/T 28181详解:国标GBT28181-2022 SIP服务器发起广播的命令流程

目录 一、定义 二、作用 1、实现信息的集中管理和分发 &#xff08;1&#xff09;信息集中 &#xff08;2&#xff09;信息分发 2、提高信息传输的可靠性和效率 &#xff08;1&#xff09;可靠性 &#xff08;2&#xff09;提高效率 3、支持多种设备和系统的互通 &am…

mongdb学习与使用

1. 基础概念 MongoDB简介&#xff1a; MongoDB是一个基于文档的NoSQL数据库&#xff0c;具有高性能、高可用性和易扩展性。数据存储在类似JSON的BSON格式中。 基本术语&#xff1a; Database&#xff08;数据库&#xff09;&#xff1a; 集合的容器。Collection&#xff08;集合…

国产强大免费WAF, 社区版雷池动态防护介绍

雷池WAF&#xff0c;基于智能语义分析的下一代 Web 应用防火墙 使用情况 我司于2023年4月23日对雷池进行测试&#xff0c;测试一个月后&#xff0c;于2023年5月24日对雷池进行正式切换&#xff0c;此时版本为1.5.1。 里程碑纪念 后续一直跟随雷池进行版本升级&#xff0c;当前…