当前位置: 首页 > news >正文

useCallback和forwardRef的联合使用

文章目录

  • 一、useCallback
  • 二、forwardRef

总结了useCallback、forwardRef中的deps,以及操作子组建时会遇到数据流不同步的问题

一、useCallback

  • useCallback可以缓存函数,这样避免组建更新导致的函数重建;
  • useCallback在函数更新以后会在deps中对比每一项,有值的变化,会更新函数中依赖项的最新值,重新创建函数;
  • 如果没有触发deps,那么这个函数不会重新创建,并且函数内使用的state值也不会变化(尤其是累加,赋值);
  • 但是useRef变量永远是最新值,一般不需要去依赖useRef值,除非他的值变化了需要去刷新函数
  • 没有deps,如果只是使用setState消息队列如:setCount((count) => count + 1),则可以拿到最值,但是也只是在函数内部使用;set函数外部依旧不会拿到最新值
  • 函数也拥有地址,会被deps捕获识别;useCallback可以缓存函数,即函数地址不会更改
import { Col, message, Row, Space } from "antd";
import { forwardRef, useCallback, useImperativeHandle, useRef, useState } from "react";export default function ParentRef() {const countRef = useRef(0);const [count, setCount] = useState(0);const [name, setName] = useState(0);// 每一次组建更新,都会生成新的函数,addFunc在其他hooks都deps中都会被识别成值产生变化const addFunc = () => {setCount(count + 1);countRef.current = countRef.current + 1;};// useCallback 中的 deps 变化,才会触发重新生成新的函数;// 没有触发deps更新,也可以调用,但是其中的依赖项使用之前的快照值(set队列函数会显示正常)const handleClick = useCallback(() => {setCount(count + 1); // 引发组件更新countRef.current = countRef.current + 1; // 不会引发组件更新;值的对比// deps 数值或者引用地址的变化,都会触发重新调用生成新的handle}, [countRef.current]);return (<div><p>Parent</p><button onClick={handleClick}>Focus Input</button><hr /></div>);
}

二、forwardRef

  • forwardRef控制子组建,useImperativeHandle暴露子组建属性;在页面代码拆分以后,组件逻辑分布分散,使用forwardRef可以快速操作子组建完成动作,而避开了传参的麻烦;
  • useImperativeHandle也有deps依赖,类似于useCallback的deps,只有deps依赖变化,才会重新创建createHandle,并更新函数内部的依赖项
  • 父组件修改state(类似异步),并且调用子组建init(类似同步),这个时候是来不及更新init中的依赖的,调用时使用了旧值;所以同步调用子组建init会拿到实时值,但是很有可能你希望获取最新值,一种解决方式是在init参数传入最新值,一种解决方式是子组建监听值的变化,调用对应的函数
  • 控制子组建init会避开数据流,导致在数据流变化之前就触发函数,需要注意init函数和最新的数据流的关系
  • 注意子组建中 await delay(0),然后setCount(count + 1);点击两次发现打印001122…,
    第一次点击:打印函数体内count = 0, delay(0) => (deps变化) => 更新函数体内count = 0(此时setCount还没有值更新)=>count = 1(实际值count);
    第二次点击:打印函数体内count = 0,delay(0)=> (deps变化) => 更新函数体内count = 1(实际值count)=>count = 1(实际值count);
    第三次点击:才会打印count为1
import { Col, message, Row, Space } from "antd";
import { forwardRef, useCallback, useImperativeHandle, useRef, useState } from "react";
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
export function ChildRefTemp(props, ref) {const inputRef = useRef(null);const [count, setCount] = useState(0);const [age, setAge] = useState(0);const handleClick = () => {inputRef.current.focus();};const countAdd = async () => {// await delay(0);// 当设置延迟,props.count先让createHandle更新,这个时候count还没有更新,还是旧值展示;// 除了第一次点击,其他时候点击两次才可以让count + 1setCount(count + 1);};// useImperativeHandle: (ref, createHandle, deps)useImperativeHandle(ref,() => {console.log("ChildRefTemp useImperativeHandle"); // 初始化也会调用一次return {init(initCount) {inputRef.current.focus();countAdd();message.success("init" + count);message.success("init props.countRef: " + props.countRef);message.success("init initCount: " + initCount);}};},// 这里的deps依赖,会导致重新调用 createHandle;如果没有依赖,获取值的时候得不到最新值// [age] 不会导致重新调用 createHandle 生成新的handle// 父组件只设置props.countRef,不去setCount,不会导致子组建接收到最新的props.countRef;// 父组件setCount,子组件接收到最新的props.count,导致子组件并没有重新渲染,只要这里的值判断改变,createHandle 中就可以重新最新的数据[props.countRef]);return (<div><input type="text" ref={inputRef} /><button onClick={handleClick}>Focus Input</button><Row style={{ marginTop: 10 }}><Col><Space><span style={{ color: "red" }}>ParentRefcount: {props.count}</span><span style={{ color: "red" }}>ParentRef countRef: {props.countRef}</span><span>count: {count}</span></Space></Col></Row></div>);
}
// forwardRef: (component, props) => ref => component(props, ref)
const ChildRef = forwardRef(ChildRefTemp);export default function ParentRef() {const childRef = useRef(null);const countRef = useRef(0);const [count, setCount] = useState(0);const [name, setName] = useState(0);// 每一次组建更新,都会生成新的函数,addFunc在其他hooks都deps中都会被识别成值产生变化const addFunc = () => {setCount(count + 1);countRef.current = countRef.current + 1;childRef.current.init();};// useCallback 中的 deps 变化,才会触发重新生成新的函数;// 没有触发deps更新,也可以调用,但是其中的依赖项使用之前的快照值(set队列函数会显示正常)const handleClick = useCallback(() => {setCount(count + 1); // 引发组件更新// setCount((count) => count + 1); // 消息队列countRef.current = countRef.current + 1; // 不会引发组件更新;值的对比childRef.current.init(countRef.current);// message.success("handleClick" + count);// deps 数值或者引用地址的变化,都会触发重新调用生成新的handle}, [countRef.current]);return (<div><p>Parent</p><button onClick={handleClick}>Focus Input</button><hr /><p>ChildRef</p>// handleClick 函数也拥有地址,会被deps捕获识别;useCallback可以缓存函数,即函数地址不会更改<ChildRef ref={childRef} count={count} countRef={countRef.current} name={name} handleClick={handleClick} /></div>);
}

相关文章:

useCallback和forwardRef的联合使用

文章目录 一、useCallback二、forwardRef 总结了useCallback、forwardRef中的deps&#xff0c;以及操作子组建时会遇到数据流不同步的问题 一、useCallback useCallback可以缓存函数&#xff0c;这样避免组建更新导致的函数重建&#xff1b;useCallback在函数更新以后会在deps中…...

C# .NET CORE 开发问题汇总

1. error MSB4803: .NET Core 版本的 MSBuild 不支持“ResolveComReference”。请使用 .NET Framework 版本的 MSBuild。 引用了一个COM组件, 使用donet 命令时,提示不支持, 可以先将项目设置为x86以构建, 将COM引用添加到核心项目中&#xff0c;构建它&#xff0c;在obj\x86\…...

【C语言】拆数字组成最大数

相信你是最棒哒&#xff01;&#xff01;&#xff01; 文章目录 题目描述 正确代码 法一注释版 简洁版 法二注释版 简洁版 题目描述 任意输入一个自然数&#xff0c;输出该自然数的各位数字组成的最大数。例如&#xff0c;输入 1593 &#xff0c;则输出为 9531 。 输入描述 …...

【Git系列】根据提交打印邮箱

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

Nginx在处理客户端请求的并发性发面是否依赖Linux的多线程原理

Nginx在处理客户端请求的并发性发面是否依赖Linux的多线程原理 Nginx 在处理客户端请求的并发性方面&#xff0c;并不依赖于 Linux 的多线程原理。 Nginx 的并发处理主要基于 事件驱动模型 和 异步非阻塞 I/O&#xff0c;而不是传统的多线程或多进程模型。 Nginx 的并发处理模…...

Python生成对抗神经网络GAN预测股票及LSTMs、ARIMA对比分析ETF金融时间序列可视化

全文链接&#xff1a;https://tecdat.cn/?p38528 本文聚焦于利用生成对抗网络&#xff08;GANs&#xff09;进行金融时间序列的概率预测。介绍了一种新颖的基于经济学驱动的生成器损失函数&#xff0c;使 GANs 更适用于分类任务并置于监督学习环境中&#xff0c;能给出价格回…...

深入了解C++中const的用法

文章目录 一、C中的const如何理解&#xff1f;二、C中的const与C语言中的const有何区别&#xff1f;三、const与指针、引用的结合使用 一、C中的const如何理解&#xff1f; 在C中&#xff0c;const是一个关键字&#xff0c;用来表示常量性&#xff0c;意在告诉编译器某些变量或…...

【Linux金典面试题(上)】41道Linux金典面试问题+详细解答,包含基本操作、系统维护、网络配置、脚本编程等问题。

大家好&#xff0c;我是摇光~&#xff0c;用大白话讲解所有你难懂的知识点 之前写了一篇关于 python 的面试题&#xff0c;感觉大家都很需要&#xff0c;所以打算出一个面试专栏。 【数据分析岗】Python金典面试题 这个专栏主要针对面试大数据岗位、数据分析岗位、数据运维等…...

利用Python实现多元回归预测汽车价格

引言: AI技术的热门使得大家对机器学习有了更多的关注,作为与AI技术息息相关的一门课程,从头了解基础的机器学习算法就显得十分有必要,如:梯度下降,线性回归等。 正文: 本文将讲解线性回归中多元回回归的案例 机器学习大致可以分为监督学习,非监督学习、半监督学习还…...

抓包软件fiddler和wireshark使用手册

fiddler官方文档 Fiddler 抓包教程1 Fiddler 抓包教程2 wireshark抓包学习 2添加链接描述 ip 过滤 ip.src_host ip.dst_host ip.addr mac 过滤 eth.src eth.dst eth.addr 端口过滤 tcp.port tcp.srcport tcp.dstport 协议类型过滤 arp dhcp 规则组合 and or...

初识三大 Observer

文章目录 ResizeObserver、MutationObserver和IntersectionObserver用MutationObserver实现图片懒加载MutationObserver 兼容性问题IntersectionObserver 应用MutationObserver和IntersectionObserver的区别IntersectionObserver 实例示例一&#xff1a;图片懒加载示例二&#…...

Eclipse MAT(Memory Analyzer Tool) 使用手册

参考&#xff1a;JAVA内存泄露使用MAT(Memory Analyzer Tool)快速定位代码 Eclipse MAT 1.15.0提示JDK版本最低需要使用17版本的&#xff0c;如果不想安装可以下载ZIP包&#xff0c;或者使用较低版本的MAT。 为了避免下载的17版本JDK和本地环境干扰&#xff0c;可以直接在MAT配…...

TongWe7.0-东方通TongWeb控制台无法访问 排查

**问题描述&#xff1a;**无法访问TongWeb的控制台 逐项排查&#xff1a; 1、控制台访问地址是否正确&#xff1a;http://IP:9060/console #IP是服务器的实际IP地址 2、确认TongWeb进程是否存在&#xff0c;执行命令&#xff1a;ps -ef|grep tongweb 3、确认TongWeb服务启动…...

Ariba Procurement: Administration_Master data

采购主数据集成Procurement Master Data Integration 注意&#xff1a;并非所有元素都是必需的&#xff0c;数据元素的名称可能根据ERP的不同&#xff0c;有所不同。 Types of Master Data Accounting 在SAP Ariba中的各种会计元素字段中&#xff0c;填充有效值选择列表。建…...

爬虫学习案例4

爬取猪八戒网站数据&#xff1a;2024-12-12 使用xpath解析元素&#xff0c;安装依赖库 pip install lxml使用selenium步骤我的上篇博客有提到&#xff0c;这里就不重复了 selenium使用博客导航 # 安装pip install lxml,使用xpath from lxml import etree import time from s…...

Angular模块化应用构建详解

文章目录 前言一、理解Angular模块&#xff08;NgModule&#xff09;二、创建功能模块三、懒加载模块以提高性能四、共享模块五、库模块六、最佳实践与注意事项七、案例研究&#xff1a;重构电子商务平台结语 前言 Angular是一款由Google支持的、用于构建动态Web应用程序的前端…...

51c大模型~合集89

我自己的原文哦~ https://blog.51cto.com/whaosoft/12815167 #OpenAI很会营销 而号称超强AI营销的灵感岛实测成效如何&#xff1f; OpenAI 是懂营销的&#xff0c;连续 12 天发布&#xff0c;每天一个新花样&#xff0c;如今刚过一半&#xff0c;热度依旧不减。 毫无疑问&…...

【蓝桥杯备战】Day 1

1.基础题目 LCR 018.验证回文串 给定一个字符串 s &#xff0c;验证 s 是否是 回文串 &#xff0c;只考虑字母和数字字符&#xff0c;可以忽略字母的大小写。 本题中&#xff0c;将空字符串定义为有效的 回文串 。 示例 1: 输入: s "A man, a plan, a canal: Panama…...

FedAdam算法:供给方信用,数据质量;更新一致性

FedAdam算法:供给方信用,数据质量;更新一致性 FedAdam算法概述 FedAdam是一种联邦学习(Federated Learning)算法。联邦学习是一种机器学习技术,它允许在多个设备或数据中心(称为客户端)上训练模型,而无需将数据集中到一个中央服务器,从而保护数据隐私。FedAdam主要用于…...

内存卡格式化后的数据恢复全攻略

一、内存卡格式化简述 内存卡&#xff0c;作为现代电子设备中不可或缺的存储媒介&#xff0c;广泛应用于手机、相机、行车记录仪等各类设备中。然而&#xff0c;在使用过程中&#xff0c;我们可能会遇到内存卡需要格式化的情况。格式化是一种将内存卡上的所有数据和文件系统清…...

docker详细操作--未完待续

docker介绍 docker官网: Docker&#xff1a;加速容器应用程序开发 harbor官网&#xff1a;Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台&#xff0c;用于将应用程序及其依赖项&#xff08;如库、运行时环…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

C++.OpenGL (14/64)多光源(Multiple Lights)

多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...

C#中的CLR属性、依赖属性与附加属性

CLR属性的主要特征 封装性&#xff1a; 隐藏字段的实现细节 提供对字段的受控访问 访问控制&#xff1a; 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性&#xff1a; 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑&#xff1a; 可以…...

NPOI Excel用OLE对象的形式插入文件附件以及插入图片

static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...

【R语言编程——数据调用】

这里写自定义目录标题 可用库及数据集外部数据导入方法查看数据集信息 在R语言中&#xff0c;有多个库支持调用内置数据集或外部数据&#xff0c;包括studentdata等教学或示例数据集。以下是常见的库和方法&#xff1a; 可用库及数据集 openintro库 该库包含多个教学数据集&a…...

湖北理元理律师事务所:债务清偿方案中的法律技术革新

文/金融法律研究组 当前债务服务市场存在结构性矛盾&#xff1a;债权人追求快速回款&#xff0c;债务人需要喘息空间。湖北理元理律师事务所通过创新法律技术&#xff0c;在《企业破产法》《民法典》框架下构建梯度清偿模型&#xff0c;实现多方利益平衡。 一、个人债务优化的…...

Go 语言中switch case条件分支语句

1. 基本语法 package main import "fmt" func main() {var extname ".css"switch extname {case ".html":fmt.Println("text/html")case ".css":fmt.Println("text/css") // text/csscase ".js":fmt.…...