ReactHooks(完结)
上期戳here
ReactHooks[三]
- 一.memo 函数
- 1.1 语法格式
- 二. useMemo
- 2.1 问题引入
- 2.2 语法格式
- 2.3 使用 useMemo 解决刚才的问题
- 三.useCallback
- 3.1 useMemo和useCallback区别
- 3.2 语法格式
- 四.useTransition
- 4.1 问题引入
- 4.2 语法格式
- 4.3 使用 isPending 展示加载状态
- 4.4 注意事项
- 五.useDeferredValue
- 5.1 问题引入
- 5.2 语法格式
- 5.3 延迟一个值与防抖和节流之间有什么不同
- 5.4 表明内容已过时
一.memo 函数
当父组件被重新渲染的时候,也会触发子组件的重新渲染,这样就多出了无意义的性能开销。使用 React.memo() 可以将组件进行缓存。
1.1 语法格式
const 组件 = React.memo(函数式组件)
import React, { useEffect, useState } from 'react'// 父组件
export const Father: React.FC = () => {// 定义 count 和 flag 两个状态const [count, setCount] = useState(0)const [flag, setFlag] = useState(false)return (<><h1>父组件</h1><p>count 的值是:{count}</p><p>flag 的值是:{String(flag)}</p><button onClick={() => setCount((prev) => prev + 1)}>+1</button><button onClick={() => setFlag((prev) => !prev)}>Toggle</button><hr /><Son num={count} /></>)
}// 子组件:依赖于父组件通过 props 传递进来的 num
//React.memo 包裹的子组件,只有props变化了,才会被重新渲染
export const Son: React.FC<{ num: number }> = React.memo(({ num }) => {useEffect(() => {console.log('触发了子组件的渲染')})return (<><h3>子组件 --- {num}</h3></>)
})
二. useMemo
如果点击 +1 按钮,发现count自增,flag值没有发生变化,但是tips函数也会重新执行。
2.1 问题引入
// 父组件
export const Father: React.FC = () => {// 定义 count 和 flag 两个状态const [count, setCount] = useState(0)const [flag, setFlag] = useState(false)// 根据布尔值进行计算,动态返回内容const tips = () => {console.log('触发了 tips 的重新计算')return flag ? <p>哪里贵了,不要睁着眼瞎说好不好</p> : <p>这些年有没有努力工作,工资涨没涨</p>}return (<><h1>父组件</h1><p>count 的值是:{count}</p><p>flag 的值是:{String(flag)}</p>{tips()}<button onClick={() => setCount((prev) => prev + 1)}>+1</button><button onClick={() => setFlag((prev) => !prev)}>Toggle</button><hr /><Son num={count} /></>)
}
我们希望如果 flag 没有发生变化,则避免 tips 函数的重新计算,从而优化性能。此时需要用到 React Hooks 提供的 useMemo API。
2.2 语法格式
const memorizedValue = useMemo(cb, array)
const memoValue = useMemo(() => {return 计算得到的值
}, [value]) // 表示监听 value 的变化
- cb:这是一个函数,用户处理计算的逻辑,必须使用 return 返回计算的结果;
- array:这个数组中存储的是依赖项,只要依赖项发生变化,都会触发 cb 的重新执行。
不传数组,每次更新都会重新计算空数组,只会计算一次依赖对应的值,对应的值发生变化时会重新执行 cb
2.3 使用 useMemo 解决刚才的问题
//导入 useMemo:
import React, { useEffect, useState, useMemo } from 'react'
//在 Father 组件中,使用 useMemo 对 tips 进行改造:
// 根据布尔值进行计算,动态返回内容
const tips = useMemo(() => {console.log('触发了 tips 的重新计算')return flag ? <p>哪里贵了,不要睁着眼瞎说好不好</p> : <p>这些年有没有努力工作,工资涨没涨</p>
}, [flag])
三.useCallback
3.1 useMemo和useCallback区别
| 名称 | 返回值 |
|---|---|
| useMemo | 变量 |
| useCallback | 函数 |
3.2 语法格式
const memoCallback = useCallback(cb, array)
- cb 是需要被缓存的函数
- array 是依赖项列表,当 array 中的依赖项变化时才会重新执行 useCallback。
- 如果省略 array,则每次更新都会重新计算
- 如果 array 为空数组,则只会在组件第一次初始化的时候计算一次
- 如果 array 不为空数组,则只有当依赖项的值变化时,才会重新计算
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></>)
}
四.useTransition
4.1 问题引入
import React, { useState } from 'react'export const TabsContainer: React.FC = () => {// 被激活的标签页的名字const [activeTab, setActiveTab] = useState('home')// 点击按钮,切换激活的标签页const onClickHandler = (tabName: string) => {setActiveTab(tabName)}return (<div style={{ height: 500 }}><TabButton isActive={activeTab === 'home'} onClick={() => onClickHandler('home')}>首页</TabButton><TabButton isActive={activeTab === 'movie'} onClick={() => onClickHandler('movie')}>电影</TabButton><TabButton isActive={activeTab === 'about'} onClick={() => onClickHandler('about')}>关于</TabButton><hr />{/* 根据被激活的标签名,渲染对应的 tab 组件 */}{activeTab === 'home' && <HomeTab />}{activeTab === 'movie' && <MovieTab />}{activeTab === 'about' && <AboutTab />}</div>)
}// Button 组件 props 的 TS 类型
type TabButtonType = React.PropsWithChildren & { isActive: boolean; onClick: () => void }
// Button 组件
const TabButton: React.FC<TabButtonType> = (props) => {const onButtonClick = () => {props.onClick()}return (<button className={['btn', props.isActive && 'active'].join(' ')} onClick={onButtonClick}>{props.children}</button>)
}// Home 组件
const HomeTab: React.FC = () => {return <>HomeTab</>
}// Movie 组件
const MovieTab: React.FC = () => {const items = Array(100000).fill('MovieTab').map((item, i) => <p key={i}>{item}</p>)return items
}// About 组件
const AboutTab: React.FC = () => {return <>AboutTab</>
}
4.2 语法格式
import { useTransition } from 'react';function TabContainer() {const [isPending, startTransition] = useTransition();// ……
}
- 参数:
- 调用 useTransition 时不需要传递任何参数
- 返回值(数组):
- isPending 布尔值:是否存在待处理的 transition【是否存在待渲染的组件】,如果值为 true,说明页面上存在待渲染的部分,可以给用户展示一个加载的提示;
- startTransition 函数:调用此函数,可以把状态的更新标记为低优先级的,不阻塞 UI 对用户操作的响应;
import React, { useState, useTransition } from 'react'export const TabsContainer: React.FC = () => {// 被激活的标签页的名字const [activeTab, setActiveTab] = useState('home')const [, startTransition] = useTransition()// 点击按钮,切换激活的标签页const onClickHandler = (tabName: string) => {startTransition(() => {setActiveTab(tabName)})}// 省略其它代码...
}
4.3 使用 isPending 展示加载状态
//调用 useTransition 期间,接收 isPending 参数:
const [isPending, startTransition] = useTransition()
// 将标签页的渲染,抽离到 renderTabs 函数中:
// 用于渲染标签页的函数
const renderTabs = () => {if (isPending) return <h3>Loading...</h3>switch (activeTab) {case 'home':return <HomeTab />case 'movie':return <MovieTab />case 'about':return <AboutTab />}
}
4.4 注意事项
- 传递给 startTransition 的函数必须是同步的。React 会立即执行此函数,并将在其执行期间发生的所有状态更新标记为 transition。如果在其执行期间,尝试稍后执行状态更新,这些状态更新不会被标记为 transition。
- 标记为 transition 的状态更新将被其他状态更新打断。
- transition 更新不能用于控制文本输入。
五.useDeferredValue
5.1 问题引入
transition更新不能用于控制文本输入,会导致中间状态丢失。
import React, { useState, useTransition } from 'react'// 父组件
export const SearchBox: React.FC = () => {const [kw, setKw] = useState('')// 1. 调用 useTransition 函数const [, startTransition] = useTransition()const onInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {// 2. 将文本框状态更新标记为“低优先级”,会导致中间的输入状态丢失startTransition(() => {setKw(e.currentTarget.value)})}return (<div style={{ height: 500 }}><input type="text" value={kw} onChange={onInputChange} /><hr /><SearchResult query={kw} /></div>)
}// 子组件,渲染列表项
const SearchResult: React.FC<{ query: string }> = (props) => {if (!props.query) returnconst items = Array(40000).fill(props.query).map((item, i) => <p key={i}>{item}</p>)return items
}
5.2 语法格式
import { useState, useDeferredValue } from 'react';function SearchPage() {const [kw, setKw] = useState('');// 根据 kw 得到延迟的 kwconst deferredKw = useDeferredValue(kw);// ...
}
useDeferredValue 的返回值为一个延迟版的状态
- 在组件首次渲染期间,返回值将与传入的值相同
- 在组件更新期间,React 将首先使用旧值重新渲染 UI 结构,这能够跳过某些复杂组件的 rerender,从而提高渲染效率。随后,React 将使用新值更新 deferredValue,并在后台使用新值重新渲染是一个低优先级的更新。这也意味着,如果在后台使用新值更新时 value 再次改变,它将打断那次更新。
注意:需要配合React.memo对子组件缓存使用。
// 1. 按需导入 useDeferredValue 这个 Hooks API
import React, { useState, useDeferredValue } from 'react'// 父组件
export const SearchBox: React.FC = () => {const [kw, setKw] = useState('')// 2. 基于 kw 的值,为其创建出一个延迟版的 kw 值,命名为 deferredKwconst deferredKw = useDeferredValue(kw)const onInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {setKw(e.currentTarget.value)}return (<div style={{ height: 500 }}><input type="text" value={kw} onChange={onInputChange} /><hr />{/* 3. 将延迟版的 kw 值,传递给子组件使用 */}<SearchResult query={deferredKw} /></div>)
}// 子组件,渲染列表项
// 4. 子组件必须使用 React.memo() 进行包裹,这样当 props 没有变化时,会跳过子组件的 rerender
const SearchResult: React.FC<{ query: string }> = React.memo((props) => {if (!props.query) returnconst items = Array(40000).fill(props.query).map((item, i) => <p key={i}>{item}</p>)return items
})
5.3 延迟一个值与防抖和节流之间有什么不同
面试可能会问到哦~:延迟一个值与防抖和节流之间有什么不同?
- 防抖: 在用户停止输入一段时间之后再更新列表。【搜索框常用】
- 节流: 是指每隔一段时间更新列表。

5.4 表明内容已过时
// 1. 按需导入 useDeferredValue 这个 Hooks API
import React, { useState, useDeferredValue } from 'react'// 父组件
export const SearchBox: React.FC = () => {const [kw, setKw] = useState('')// 2. 基于 kw 的值,为其创建出一个延迟版的 kw 值const deferredValue = useDeferredValue(kw)const onInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {setKw(e.currentTarget.value)}return (<div style={{ height: 500 }}><input type="text" value={kw} onChange={onInputChange} /><hr />{/* 3. 将延迟版的 kw 值,传递给子组件使用 */}<div style={{ opacity: kw !== deferredValue ? 0.3 : 1, transition: 'opacity 0.5s ease' }}><SearchResult query={deferredValue} /></div></div>)
}
ReactHooks 到这就完结啦,感谢大家的喜欢❥(^_-)
相关文章:
ReactHooks(完结)
上期戳here ReactHooks[三] 一.memo 函数1.1 语法格式 二. useMemo2.1 问题引入2.2 语法格式2.3 使用 useMemo 解决刚才的问题 三.useCallback3.1 useMemo和useCallback区别3.2 语法格式 四.useTransition4.1 问题引入4.2 语法格式4.3 使用 isPending 展示加载状态4.4 注意事项…...
【数据中台】大数据管理平台建设方案(原件资料)
建设大数据管理中台,按照统一的数据规范和标准体系,构建统一数据采集﹣治理﹣共享标准、统一技术开发体系、统一接口 API ,实现数据采集、平台治理,业务应用三层解耦,并按照统一标准格式提供高效的…...
UE5+OpenCV配置(Windows11系统)
一、概述 因为需要在UE5中使用OpenCV这些工具进行配置,所以在网络上参考借鉴一些资料进行配置。查询到不少的资料,最后将其配置成功。在这里顺便记录一下自己的配置成功的过程。 二、具体过程 (一)版本 使用Windows11系统、UE5.…...
自研Vue3开源Tree组件:节点拖拽bug修复
当dropType为after,且dropNode为父节点时,bug出现了: bug原因:插入扁平化列表的位置insertIndex计算的不对: 正确的逻辑,同inner要算上子孙节点所占的位置: bug修复!...
SSM学习9:SpringBoot简介、创建项目、配置文件、多环节配置
简介 SpringBoot式用来简化Spring应用的初始搭建以及开发过程的一个框架 项目搭建 File -> New -> Project 选中pom.xml文件,设置为maven项目 项目启动成功 可以访问BasicController中的路径 配置文件 在resources目录下 application.properties 默…...
Java面试题---索引
什么是索引 索引是用来高效获取数据的存储结构如同字典的目录一样,数据库的索引通常使用btree来实现,索引树的节点和数据地址相关联,查询的时候在索引树种进行高效搜索,然后根据数据地址获取数据。索引提高了搜索的效率同时增加了…...
ollama本地部署大语言模型记录
目录 安装Ollama更改模型存放位置 拉取模型GemmaMistralQwen1.5(通义千问)codellama 部署Open webui测试性能知识广度问题1问题2 代码能力总结 最近突然对大语言模型感兴趣 同时在平时的一些线下断网的CTF比赛中,大语言模型也可以作为一个能对话交互的高级知识检索…...
【C++红黑树应用】模拟实现STL中的map与set
目录 🚀 前言一: 🔥 红黑树的修改二: 🔥 红黑树的迭代器 三: 🔥 perator() 与 operator--() 四: 🔥 红黑树相关接口的改造✨ 4.1 Find 函数的改造✨ 4.2 Insert 函数的改…...
前端实习手计(5):班味十足?!
自我感觉没有班味!!!每天还是快快乐乐上班哇,是愉快的一周~这周没有太多活咯,基本就是修修改改改代码学习。真的感觉自己写的代码就是乱七八糟,只要能跑起来有效果就行(我不是合格的处女座哈哈哈…...
Duix AI 太上瘾,让我熬夜体验的AI女友
✨点击这里✨:🚀原文链接:(更好排版、视频播放、社群交流、最新AI开源项目、AI工具分享都在这个公众号!) Duix AI 太上瘾,让我熬夜体验的AI女友 开启 Duix AI 女友的奇妙之旅_ Hi,这…...
php判断某个目录下是否存在文件
/*** 判断字符串是否以什么结尾* param String $haystack 字符串* param String $needle 结尾* return Boolean*/ function endWith($haystack, $needle) {$length strlen($needle);if ($length 0) {return true;}return (substr($haystack, -$length) $needle); } /***…...
重塑互联网生态:探索Web 3.0、大数据与隐私保护的新篇章
引言:互联网的新纪元 随着互联网技术的日新月异,我们正迈入一个全新的时代,其中Web 3.0、大数据以及隐私保护成为塑造未来互联网生态的三大核心力量。它们不仅改变了我们与互联网交互的方式,更深刻地影响着社会的方方面面。 Web…...
HR模块中PA信息类型的相关函数
目录 1、新增、删除,修改:HR_INFOTYPE_OPERATION新增:INS删除:DEL修改:MOD 2、读取PA信息类型:HR_READ_INFOTYPE3、入职,生成新工号用:HR_PAD_HIRE_EMPLOYEE4、加锁:BAPI…...
c# 日期类型变量默认值
DateTime类型是比较常用的变量类型,但是以前处理都比较业余,下面总结2中常用方式 这次把它总结下: DateTime t1 default(DateTime); DateTime t2 DateTime.MinValue; 这样t1,t2 的值都是 {0001/1/1 0:00:00} PS: 由于DateTi…...
设计模式实战:任务调度系统的设计与实现
问题描述 设计一个任务调度系统,支持任务的创建、调度、执行和状态管理。系统需要确保任务的执行过程可以被灵活调度,并且支持任务状态的跟踪和通知功能。 设计分析 命令模式 命令模式用于将请求封装成对象,从而使我们可以用不同的请求、队列或日志来参数化其他对象。任…...
代码中的特殊注释
代码中特殊注释——TODO、FIXME、XXX、HACK_fix me todo hack-CSDN博客 代码中特殊注释——TODO、FIXME、XXX、HACK TODO:英语翻译为待办事项,备忘录。如果代码中有该标识,说明在标识处有功能代码待编写,待实现的功能在说明中会…...
ubuntu20.04.6 安装Skywalking 10.0.1
1.前置准备 1.1. **jdk17(Skywalking10 jdk22不兼容,用17版本即可)**安装: https://blog.csdn.net/CsethCRM/article/details/140768670 1.2. elasticsearch安装: https://blog.csdn.net/CsethCRM/article/details…...
C++:map和set
hello,各位小伙伴,本篇文章跟大家一起学习《C:map和set》,感谢大家对我上一篇的支持,如有什么问题,还请多多指教 ! 如果本篇文章对你有帮助,还请各位点点赞!!…...
深入理解二叉搜索树:定义、操作及平衡二叉树
引言 二叉搜索树(Binary Search Tree,BST)是一种特殊的二叉树结构,每个节点的左子树节点值小于根节点值,而右子树节点值大于根节点值。二叉搜索树在计算机科学中有着广泛的应用,尤其在动态查找表和优先队列…...
vue3组件通信(二)
组件通信 一.$attrs(祖>孙间接)二、$refs()父>子, $parent()子>父三.provide,inject(祖>孙直接)四.pinia五.slot1.默认插槽2.具名插槽3.作用域插槽 一.$attrs(祖>孙间接) $attrs用于实现当前组件的父组…...
Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...
安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...
