React Hooks小记(十)_useCallback

useCallback

1. 语法格式

之前我们所学的 useMemo 能够达到缓存某个变量值的效果,而当前要学习的 useCallback 用来对组件内的函数进行缓存,它返回的是缓存的函数。它的语法格式如下:

const memoCallback = useCallback(cb, array)

useCallback 会返回一个 memorized 回调函数供组件使用,从而防止组件每次 rerender 时反复创建相同的函数,能够节省内存开销,提高性能。其中:

1. cb 是一个函数,用于处理业务逻辑,这个 cb 就是需要被缓存的函数

2. array 是依赖项列表,当 array 中的依赖项变化时才会重新执行 useCallback

a. 如果省略 array,则每次更新都会重新计算

b. 如果 array 为空数组,则只会在组件第一次初始化的时候计算一次

c. 如果 array 不为空数组,则只有当依赖项的值变化时,才会重新计算

2. 基本示例

接下来,我们通过下面的例子演示使用 useCallback 的必要性:当输入框触发 onChange 事件时,会给 kw 重新赋值。

kw 值的改变会导致组件的 rerender,而组件的 rerender 会导致反复创建 onKwChange 函数并添加到 Set 集合中,造成了不必要的内存浪费。代码如下:

import React, { useState, useCallback } from 'react'// 用来存储函数的 set 集合
const set = new Set()export const Search: React.FC = () => {const [kw, setKw] = useState('')const onKwChange = (e: React.ChangeEvent<HTMLInputElement>) => {setKw(e.currentTarget.value)}// 把 onKwChange 函数的引用,存储到 set 集合中set.add(onKwChange)// 打印 set 集合中元素的数量console.log('set 中函数的数量为:' + set.size)return (<><input type="text" value={kw} onChange={onKwChange} /><hr /><p>{kw}</p></>)
}

运行上面的代码,我们发现每次文本框的值发生变化,都会打印 set.size 的值,而且这个值一直在自增 +1,因为每次组件 rerender 都会创建一个新的 onKwChange 函数添加到 set 集合中。

为了防止 Search 组件 rerender 时每次都会重新创建 onKwChange 函数,我们可以使用 useCallback 对这个函数进行缓存。改造后的代码如下:

import React, { useState, useCallback } from 'react'// 用来存储函数的 set 集合
const set = new Set()export const Search: React.FC = () => {const [kw, setKw] = useState('')const onKwChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {setKw(e.currentTarget.value)}, [])// 把 onKwChange 函数的引用,存储到 set 集合中set.add(onKwChange)// 打印 set 集合中元素的数量console.log('set 中函数的数量为:' + set.size)return (<><input type="text" value={kw} onChange={onKwChange} /><hr /><p>{kw}</p></>)
}

运行改造后的代码,我们发现无论 input 的值如何发生变化,每次打印的 set.size 的值都是 1。证明我们使用 useCallback 实现了对函数的缓存。

3. 搜索案例

3.1 问题引入

1、导入需要的 hooks 函数,并定义需要的 TS 类型:

import React, { useEffect, useState, useCallback } from 'react'// 文本框组件的 props 类型
type SearchInputType = { onChange: (e: React.ChangeEvent<HTMLInputElement>) => void }
// 单词对象的 TS 类型
type WordType = { id: number; word: string }

2、定义 SearchInput 搜索框子组件,接收父组件传递进来的 onChange 处理函数,每当 input 触发 onChange 事件时,调用 props.onChange 进行处理:

// 子组件
const SearchInput: React.FC<SearchInputType> = (props) => {useEffect(() => {console.log('触发了 SearchInput 的 rerender')})return <input onChange={props.onChange} placeholder="请输入搜索关键字" />
}

3、定义 SearchResult 搜索结果子组件,接收父组件传递进来的 query 搜索关键字,在 useEffect 中监听 props.query 的变化,从而请求搜索的结果:

// 子组件:搜索结果
const SearchResult: React.FC<{ query: string }> = (props) => {const [list, setList] = useState<WordType[]>([])useEffect(() => {// 如果 query 为空字符串,则清空当前的列表if (!props.query) return setList([])// 查询数据fetch('https://api.liulongbin.top/v1/words?kw=' + props.query).then((res) => res.json()).then((res) => {// 为列表赋值setList(res.data)})}, [props.query])// 渲染列表数据return list.map((item) => <p key={item.id}>{item.word}</p>)
}

4、定义父组件 SearchBox 并渲染 SearchInput 组件和 SearchResult 组件。在父组件中监听 SearchInput 的 onChange 事件,并把父组件中定义的处理函数 onKwChange 传递进去。同时,把父组件中定义的搜索关键字 kw 传递给 SearchResult 组件。示例代码如下:

// 父组件
export const SearchBox: React.FC = () => {const [kw, setKw] = useState('')const onKwChange = (e: React.ChangeEvent<HTMLInputElement>) => {setKw(e.currentTarget.value)}return (<div style={{ height: 500 }}><SearchInput onChange={onKwChange} /><hr /><SearchResult query={kw} /></div>)
}

5、经过测试后,我们发现:

其实,子组件根本不需要被重新渲染,因为 props.onChange 函数的处理逻辑没有发生变化,只是它的引用每次都在变。为了解决这个问题,我们需要用到 useCallbackReact.memo

​ 1. 每当子组件的文本框内容发生变化,都会调用 props.onChange 把数据发送给父组件。

​ 2. 相应的,父组件通过 onKwChange 函数可以获取到子组件的值,并把值更新到 kw 中。当 kw 发生变化,会触发父组件的 rerender。

​ 3. 而父组件的 rerender 又会重新生成 onKwChange 函数并把函数的引用作为 props 传递给子组件。

​ 4. 这样,子组件就监听到了 props 的变化,最终导致子组件的 rerender。

其实,子组件根本不需要被重新渲染,因为 props.onChange 函数的处理逻辑没有发生变化,只是它的引用每次都在变。为了解决这个问题,我们需要用到 useCallbackReact.memo

3.2 问题解决

1、首先,我们需要让子组件 SearchInput 被缓存,所以我们需要使用 React.memo 对其进行改造:

// 子组件:搜索框
const SearchInput: React.FC<SearchInputType> = React.memo((props) => {useEffect(() => {console.log('触发了 SearchInput 的 rerender')})return <input onChange={props.onChange} placeholder="请输入搜索关键字" />
})

2、使用 React.memo 对组件进行缓存后,如果子组件的 props 在两次更新前后没有任何变化,则被 memo 的组件不会 rerender。

所以为了实现 SearchInput 的缓存,还需要基于 useCallback 把父组件传递进来的 onChange 进行缓存。

在父组件中针对 onKwChange 调用 useCallback,示例代码如下:

const onKwChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {setKw(e.currentTarget.value)
}, []) 

经过测试,我们发现每当文本框内容发生变化,不会导致 SearchInput 组件的 rerender。

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

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

相关文章

【ONLYOFFICE 8.1】的安装与使用——功能全面的 PDF 编辑器、幻灯片版式、优化电子表格的协作

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、引言二、ONLYOFFICE 简介三、安装1. Windows/Mac 安装2. 文档开发者版安装安装前准备使用 Docker 安装使用 Linux 发行版安装配置 ONLYOFFICE 文档开发者版集成和开发 四、使用1. 功能全面的 PDF 编辑器PDF 查看和导航P…

小公司做自动化的困境

1. 人员数量不够 非常常见的场景, 开发没几个, 凭什么测试要那么多, 假设这里面有3个测试, 是不是得有1个人会搞框架? 是不是得有2人搞功能测试, 一个人又搞框架, 有些脚本, 真来得及吗? 2. 人员基础不够 现在有的大公司, 是这样子协作的, 也就是某模块需求谁谁测试的, 那么…

【高级篇】性能优化:解锁数据库潜能的艺术(十)

引言 随着基础篇的结束,我们进入了MySQL高级篇的旅程,首站便是性能优化。在当今数据驱动的世界里,数据库的性能直接影响着应用的响应速度和用户体验。本章,我们将深入探讨查询优化、服务器参数调整、InnoDB引擎调优以及慢查询日志分析等关键领域,帮助你掌握解锁数据库潜能…

GEOS学习笔记(三)

LineString类型GEOS_LINESTRING double line[] {-100.0,0.0, 100.0,0.0}; GEOSCoordSequence* seq GEOSCoordSeq_copyFromBuffer( line, 2, 0, 0); GEOSGeometry* p1 GEOSGeom_createLineString(seq); GEOSGeometry* p2 GEOSGeomFromWKT("LINESTRING (100 -100.0,100.0…

交易例子----qmt实盘分钟交易例子,提供交易源代码

今天给大家一个利用qmt_trader交易策略&#xff0c;我现在实盘使用的系统是自己开发的&#xff0c;只需要把qmt_trader当中第三方库使用就可以&#xff0c;源代码开源开源直接下载 量化系统--开源强大的qmt交易系统&#xff0c;提供源代码 参考教程使用&#xff0c;下载当第三…

ONLYOFFICE桌面编辑器8.1版:个性化编辑和功能强化的全面升级

ONLYOFFICE是一款全面的办公套件&#xff0c;由Ascensio System SIA开发。该软件提供了一系列与微软Office系列产品相似的办公工具&#xff0c;包括处理文档&#xff08;ONLYOFFICE Document Editor&#xff09;、电子表格&#xff08;ONLYOFFICE Spreadsheet Editor&#xff0…

Ubuntu Nvidia GPU驱动安装和故障排除

去官网 菜单列表下载&#xff0c;或者直接下载驱动 wget https://cn.download.nvidia.com/XFree86/Linux-x86_64/550.54.14/NVIDIA-Linux-x86_64-550.54.14.run 安装驱动 /data/install/NVIDIA-Linux-x86_64-550.54.14.run 执行命令&#xff0c;显示GPU情况 出错处理&…

【深度学习】tensorboard的使用

目前正在写一个训练框架&#xff0c;需要有以下几个功能&#xff1a; 1.保存模型 2.断点继续训练 3.加载模型 4.tensorboard 查询训练记录的功能 命令&#xff1a; tensorboard --logdirruns --host192.168.112.5 效果&#xff1a; import torch import torch.nn as nn impor…

java 利用poi读取wps嵌入式图片,自测

代码 主要工具类 需要引入依赖&#xff1a; mvn install:install-file -DfileC:\Users\18151\Downloads\apache-xmlbeans-bin-5.2.1-20240522\apache-xmlbeans-5.2.1\bin\xmltypes.jar -DgroupIdcn.wps -DartifactIdofficeDocument -Dversion1.0 -Dpackagingjar<dependen…

视频网站系统

摘 要 随着互联网的快速发展和人们对视频内容的需求增加&#xff0c;视频网站成为了人们获取信息和娱乐的重要平台。本论文基于SpringBoot框架&#xff0c;设计与实现了一个视频网站系统。首先&#xff0c;通过对国内外视频网站发展现状的调研&#xff0c;分析了视频网站的背景…

React@16.x(41)路由v5.x(6)常见应用场景(3)- 实现导航守卫

目录 1&#xff0c;简单实现1.1&#xff0c;监听1.2&#xff0c;控制跳转 2&#xff0c;全局封装3&#xff0c;阻止跳转 vue-router 中的导航守卫 router.beforeEach 有2个作用&#xff1a; 监听路由跳转&#xff1b;控制路由是否可以跳转。 在 React 中可以模拟实现。 1&am…

一站式uniapp优质源码项目模版交易平台的崛起与影响

一、引言 随着信息技术的飞速发展&#xff0c;软件源码已成为推动行业进步的重要力量。源码的获取、交易和流通&#xff0c;对于开发者、企业以及项目团队而言&#xff0c;具有极其重要的意义。为满足市场对高质量源码资源的迫切需求&#xff0c;一站式uniapp优质源码项目模版…

STM32开发实战:SPI接口在W25Q64 Flash存储器中的应用

摘要 本文将深入探讨STM32微控制器如何利用SPI接口与W25Q64 Flash存储器进行通信。W25Q64是一款常用的SPI串行Flash存储器&#xff0c;具有8Mbit的存储容量。本教程将指导读者完成硬件连接、SPI配置、读写操作&#xff0c;并提供实际的代码实现。 1. SPI接口概述 SPI是一种串…

激光雷达数据处理

激光雷达技术以其高精度、高效率的特点&#xff0c;已经成为地表特征获取、地形建模、环境监测等领域的重要工具。掌握激光雷达数据处理技能&#xff0c;不仅可以提升工作效率&#xff0c;还能够有效提高数据的质量和准确性&#xff0c;为决策提供可靠的数据支持。 第一章、激…

【论文解读】STUDY ON CODING TOOLS BEYOND AV1

论文下载地址:STUDY ON CODING TOOLS BEYOND AV1 摘要 开放媒体联盟最近启动了针对超越AV1的下一代视频编码工具的探索活动。 在这方面,本文介绍了一套在称为libaom的代码库之上经过研究、实施和测试的编码工具包,该代码库用于探索下一代视频压缩工具。 所提出的工具涵盖了…

Spring自带的持久层模板类:JdbcTemplate+Spring框架声明式事务管理实战

模板技术 Spring框架中提供了很多模板类来简化编程&#xff0c;使用模板类编写程序会变的简单 持久层模板JdbcTemplate JdbcTemplate是什么 JDBCTemplate是Spring Framework中的一个核心类&#xff0c;用于简化JDBC&#xff08;Java数据库连接&#xff09;代码的编写。它提供…

Gazebo给机器人添加碰撞检测属性bumper

参考&#xff1a;GAZEBO探索——给机器人加上bumper_gazebo bumper-CSDN博客 gazebo的bumper使用_gazebo bumper-CSDN博客使用URDF在Gazebo中搭建碰撞仿真(bumper)_gazebo bumper-CSDN博客 gazebo官网中bumper插件介绍 Gazebo : Tutorial : Gazebo plugins in ROS 添加的到.…

SQLite、MySQL、PostgreSQL 3个关系数据库之间优缺点对比

引言 关系数据模型以行和列的表格形式组织数据&#xff0c;在数据库管理工具中占主导地位。今天还有其他数据模型&#xff0c;包括NoSQL和NewSQL&#xff0c;但是关系数据库管理系统&#xff08;RDBMS&#xff09;仍然占主导地位用于存储和管理全球数据。 本文比较了三种实现最…

关于几种熵的计算(MATLAB)

Shannon在1948年定义了信息熵&#xff0c;并用信息熵来衡量一个事件的不确定程度。作为信息论中一个重要的基本概念&#xff0c;信息就是一种客观存在和能动的过程&#xff0c;它可以减少或者消除事件的不确定因素。一切客观事物的属性中都包含着不确定性&#xff0c;人们在没有…

mac菜单栏应用管理软件:Bartender 4 for Mac 中文激活版

Bartender 4 是一款由Bearded Men Games开发的适用于Mac操作系统的应用程序&#xff0c;它被设计用来优化和美化Mac菜单栏的功能。自从macOS Big Sur开始&#xff0c;Mac的菜单栏可以自定义&#xff0c;用户可以添加和移除各种图标。Bartender 4就是在这个背景下应运而生&#…