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

React的useEvent 和 ahooks 的 useMemorizedFn 的深度分析和对比

父组件

const TestParent: React.FC<any> = () => {const [State, setState] = useState(0);const changeFun = useCallback(() => {console.log('useCallback closure 里的  State', State);}, [State]);const changeFun_useEvent = useEvent(() => {console.log('useEvent closure 里的  State', State);});const changeFun_usememrized = useMemorizedFn(() => {console.log('useMemorizedFn closure 里的  State', State);});return (<div style={{ width: '100%', padding: '20px', backgroundColor: 'green' }}>父组件的state: {State}<button onClick={() => setState(Math.random())}>click-change state</button><TestChild changeFun={changeFun_useEvent}></TestChild><TestChild changeFun={changeFun_usememrized}></TestChild></div>);
};

子组件

const TestChild = (props: any) => {const { changeFun } = props;useEffect(() => {console.log('changeFun-》地址change了,导致了子组件刷新了。');}, [changeFun]);return (<div style={{ backgroundColor: 'pink' }}>子组件<br /><br /><button onClick={changeFun}>child click - get parent's state </button></div>);
};
React.memo(TestChild);

useEvent

已被官方废弃

useEvent 源码解析

【解释1】
1、由于每次父组件更新,都会执行到 下面的代码。这个是首要条件!
const changeFun_useEvent = useEvent(() => {
console.log('useEvent closure 里的  State', State);
});

2、其次,每次执行都会传递过来一个新的handler,自然带来了新的闭包、新的数据。

3、最后,useLayoutEffect的作用是每次数据发生更新,自动的去执行里面的方法。

4、 所以 handlerRef.current 就能拿到带着最新数据的一个handler

【解释2】

useCallback 并且依赖为[],只执行一次,地址也就永远不会变了。
那么,useEvent()return出去函数的地址永不变化。

可以解释为

1、useEvent() return 出去了一个对象,为  obj = {A:{}}2、 useCallback里的箭头函数return出去的是这个 fn=handlerRef.current;相当于一个属性 A 由于handlerRef.current指向地址是不停变化的,所以A得指向地址就是不停变化的。3、因此我们真正使用 changeFun_useEvent=useEvent(xx)的时候, 拿到的是obj。永远不变的地址。changeFun_useEvent()调用的时候拿到的就是obj.A了。就是最新的带着最新数据的一个handler
function useEvent(handler: any) {const handlerRef = useRef(null);// In a real implementation, this would run before layout effects// 这行保证handlerRef一直处于,最新的闭包、拿到最新的数据。【解释1】useLayoutEffect(() => {console.log('useLayoutEffect执行了');handlerRef.current = handler;});
//这行保证返回的数据地址永远不变,但是执行的时候拿到的最新的。【解释2】return useCallback((...args: any) => {// In a real implementation, this would throw if called during renderconst fn = handlerRef.current;return fn(...args);}, []);
}
useMemorizedFn源码解析

源码地址
【解释1】
fn在这里做依赖的原因: 由于每次父组件重新执行,都会走到useMemorizedFn里并传过来一个新的箭头函数。所以fn每次地址都是新的。也就带来了新数据的闭包。fnRef.current也就是解释2里的A的地址每次都是新的,带着新的数据的闭包。

【解释2】
这里可以解释为: const obj = {A:{}} ;
memoizedFn.current = obj;
fnRef.current = A
当执行memoizedFn.current的时候也就是去访问并执行了 obj.A

function useMemorizedFn(fn: any) {const fnRef = useRef(fn);// 这行保证fn一直处于,最新的闭包、拿到最新的数据。【解释1】//这里为什么不直接  fnRef.current =  fn  ,可参考官网。总结就是 fnRef.current的需要放到useMemo。否则reactdev tool监听不到变化。fnRef.current = useMemo(() => {console.log('useMemo执行了'); // 父级改变就执行return fn;}, [fn]);const memoizedFn = useRef<any>();// 下面保证fn引用地址不变、且每次都能拿到最新的闭包 【解释2】if (!memoizedFn.current) {memoizedFn.current = function (this: any, ...args: any) {return fnRef.current.apply(this, args);//立即执行、改变this指向、传递参数 3个作用};}return memoizedFn.current;
}
总结

由此我们看出。其实二者的原理和出发点都是一致的,都是返回的是个固定的对象obj,该对象地址不变,但是调用的方法的时候相当于调用了obj.A,此属性的指向是会一直更新的。
只不过更新的时候 :useevent用了useLayoutCallback做更新,useMemorizedFn则使用了useMemo。
保持地址不变的时候:useevent用的是useCallback ,useMemorizedFn使用的一个 !memoizedFn.current + 新固定的function 。

此文纯属个人理解,有偏差望指正。

http://www.lryc.cn/news/215081.html

相关文章:

  • 基于goframe2.5.4、vue3、tdesign-vue-next开发的全栈前后端分离的管理系统
  • LInux之在同一Tomcat下使用不同的端口号访问不同的项目
  • 梦百合上榜2023鼎革奖数字化转型先锋榜
  • 沉痛悼念科研分公司
  • Django的网站项目开发好了,该用何种方案在Centos上部署【答:Gunicorn(uWSGI)+Nginx】
  • 基于PyTorch的中文情绪分析器设计与开发
  • HT5010 音频转换器工作原理
  • ubuntu18.04如何更新到22.04
  • 嵌入式软件开发:第二部分–七个步骤计划
  • 什么是IPA,和RPA有啥区别和联系?
  • 内涝积水监测仪怎么样?万宾科技城市内涝积水监测的作用
  • 【java】命令行,包
  • Generative AI 新世界 | 文生图(Text-to-Image)领域论文解读
  • 03.从简单的sql开始
  • JS加密/解密之jsjiami在线js加密的效率问题
  • 解决【spring boot】Process finished with exit code 0的问题
  • 模电学习路径
  • 【Linux】配置JDKTomcat开发环境及MySQL安装和后端项目部署
  • Modelsim 使用教程(3)——Projects
  • pytorch复现3_GoogLenet
  • CH09_重新组织数据
  • 最新 IntelliJ IDEA 旗舰版和社区版下载安装教程(图解)
  • 优化 FPGA HLS 设计
  • LVGL库入门 01 - 样式
  • 酷克数据出席永洪科技用户大会 携手驱动商业智能升级
  • 英语教育目标转变:更加注重实际应用能力培养
  • Java中的继承和多态
  • 海外问卷调查现在还可以做吗?
  • CA证书与服务器证书
  • AI智能语音识别模块(二)——基于Arduino的语音控制MP3播放器