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,以及操作子组建时会遇到数据流不同步的问题 一、useCallback useCallback可以缓存函数,这样避免组建更新导致的函数重建;useCallback在函数更新以后会在deps中…...
C# .NET CORE 开发问题汇总
1. error MSB4803: .NET Core 版本的 MSBuild 不支持“ResolveComReference”。请使用 .NET Framework 版本的 MSBuild。 引用了一个COM组件, 使用donet 命令时,提示不支持, 可以先将项目设置为x86以构建, 将COM引用添加到核心项目中,构建它,在obj\x86\…...
【C语言】拆数字组成最大数
相信你是最棒哒!!! 文章目录 题目描述 正确代码 法一注释版 简洁版 法二注释版 简洁版 题目描述 任意输入一个自然数,输出该自然数的各位数字组成的最大数。例如,输入 1593 ,则输出为 9531 。 输入描述 …...
【Git系列】根据提交打印邮箱
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
Nginx在处理客户端请求的并发性发面是否依赖Linux的多线程原理
Nginx在处理客户端请求的并发性发面是否依赖Linux的多线程原理 Nginx 在处理客户端请求的并发性方面,并不依赖于 Linux 的多线程原理。 Nginx 的并发处理主要基于 事件驱动模型 和 异步非阻塞 I/O,而不是传统的多线程或多进程模型。 Nginx 的并发处理模…...
Python生成对抗神经网络GAN预测股票及LSTMs、ARIMA对比分析ETF金融时间序列可视化
全文链接:https://tecdat.cn/?p38528 本文聚焦于利用生成对抗网络(GANs)进行金融时间序列的概率预测。介绍了一种新颖的基于经济学驱动的生成器损失函数,使 GANs 更适用于分类任务并置于监督学习环境中,能给出价格回…...
深入了解C++中const的用法
文章目录 一、C中的const如何理解?二、C中的const与C语言中的const有何区别?三、const与指针、引用的结合使用 一、C中的const如何理解? 在C中,const是一个关键字,用来表示常量性,意在告诉编译器某些变量或…...
【Linux金典面试题(上)】41道Linux金典面试问题+详细解答,包含基本操作、系统维护、网络配置、脚本编程等问题。
大家好,我是摇光~,用大白话讲解所有你难懂的知识点 之前写了一篇关于 python 的面试题,感觉大家都很需要,所以打算出一个面试专栏。 【数据分析岗】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 实例示例一:图片懒加载示例二&#…...
Eclipse MAT(Memory Analyzer Tool) 使用手册
参考:JAVA内存泄露使用MAT(Memory Analyzer Tool)快速定位代码 Eclipse MAT 1.15.0提示JDK版本最低需要使用17版本的,如果不想安装可以下载ZIP包,或者使用较低版本的MAT。 为了避免下载的17版本JDK和本地环境干扰,可以直接在MAT配…...
TongWe7.0-东方通TongWeb控制台无法访问 排查
**问题描述:**无法访问TongWeb的控制台 逐项排查: 1、控制台访问地址是否正确:http://IP:9060/console #IP是服务器的实际IP地址 2、确认TongWeb进程是否存在,执行命令:ps -ef|grep tongweb 3、确认TongWeb服务启动…...
Ariba Procurement: Administration_Master data
采购主数据集成Procurement Master Data Integration 注意:并非所有元素都是必需的,数据元素的名称可能根据ERP的不同,有所不同。 Types of Master Data Accounting 在SAP Ariba中的各种会计元素字段中,填充有效值选择列表。建…...
爬虫学习案例4
爬取猪八戒网站数据:2024-12-12 使用xpath解析元素,安装依赖库 pip install lxml使用selenium步骤我的上篇博客有提到,这里就不重复了 selenium使用博客导航 # 安装pip install lxml,使用xpath from lxml import etree import time from s…...
Angular模块化应用构建详解
文章目录 前言一、理解Angular模块(NgModule)二、创建功能模块三、懒加载模块以提高性能四、共享模块五、库模块六、最佳实践与注意事项七、案例研究:重构电子商务平台结语 前言 Angular是一款由Google支持的、用于构建动态Web应用程序的前端…...
51c大模型~合集89
我自己的原文哦~ https://blog.51cto.com/whaosoft/12815167 #OpenAI很会营销 而号称超强AI营销的灵感岛实测成效如何? OpenAI 是懂营销的,连续 12 天发布,每天一个新花样,如今刚过一半,热度依旧不减。 毫无疑问&…...
【蓝桥杯备战】Day 1
1.基础题目 LCR 018.验证回文串 给定一个字符串 s ,验证 s 是否是 回文串 ,只考虑字母和数字字符,可以忽略字母的大小写。 本题中,将空字符串定义为有效的 回文串 。 示例 1: 输入: s "A man, a plan, a canal: Panama…...
FedAdam算法:供给方信用,数据质量;更新一致性
FedAdam算法:供给方信用,数据质量;更新一致性 FedAdam算法概述 FedAdam是一种联邦学习(Federated Learning)算法。联邦学习是一种机器学习技术,它允许在多个设备或数据中心(称为客户端)上训练模型,而无需将数据集中到一个中央服务器,从而保护数据隐私。FedAdam主要用于…...
内存卡格式化后的数据恢复全攻略
一、内存卡格式化简述 内存卡,作为现代电子设备中不可或缺的存储媒介,广泛应用于手机、相机、行车记录仪等各类设备中。然而,在使用过程中,我们可能会遇到内存卡需要格式化的情况。格式化是一种将内存卡上的所有数据和文件系统清…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...
