想要做到就要有更多的学习,你知道为什么React不把他们设为默认方法#useEvent是一个刚刚提案的原生Hook,还处于RFC。现在我们就一起来讨论下
RFC:Request for Comments 提案应用的还十分广泛
我们先看看在没有 useEvent 会出现的情况:
function Chat() { const [text, setText] = useState(''); // ???? Always a different function const onClick = () => { sendMessage(text); }; return <SendButton onClick={onClick} />; }
上面可以看到在点击事件的回调函数onClick中需要读取当前键入的文本text,就会造成onClick随着组件重新渲染一次次地重新创建,每次都会如此的重复,对于性能损耗十分大,想要优化看看下面:
function Chat() { const [text, setText] = useState(''); // ???? A different function whenever `text` changes const onClick = useCallback(() => { sendMessage(text); }, [text]); return <SendButton onClick={onClick} />; }
通过 useCallback 返回一个 memoized 回调函数。
useCallback: 返回一个 memoized 回调函数。 把内联回调函数及依赖项数组作为参数传入useCallback,它将返回该回调函数的memoized版本,该回调函数仅在某个依赖项改变时才会更新。当你把回调函数传递给经过优化的并使用引用相等性去避免非必要渲染(例如shouldComponentUpdate)的子组件时,它将非常有用。useCallback(fn, deps)相当于useMemo(() => fn, deps)。
最终使得onClick的引用始终不变但是!
onClcik这个方法有需要保证每次都要拿到最新的、正确的text,所以他的deps中就自然是设置了text—— 坏了,“又回到最初的起点~”。随着每一次keystroke,onClick又变成了上面的情况:
Always a different function
但你又不能将其从deps中移除,移除了他就只能拿到text的初始值,失去了他本该有的功能...
小 useEvent 来给他整个活????
useEvent就是为了解决此类问题,所以他干脆不要deps了,他就是一直返回一个相同的函数引用,哪怕text发生变化。当然,保证它也能拿到最新的、正确的**text**。
function Chat() { const [text, setText] = useState(''); // ✅ Always the same function (even if `text` changes) const onClick = useEvent(() => { sendMessage(text); }); return <SendButton onClick={onClick} />; }
现在好了:
onClick 的引用始终是同一个
保证每次都能拿到最新的、正确的text
当然还有其他一些场景,但是大致需求原理相同,就是不想让A因为b变化而总是重新加载,但是又因为要拿到b恰当的值,所以deps中必须b,导致不得不重新加载,掉进了“圈圈圆圆圈圈~”的陷阱。更多场景这里就不再赘述。更多案例可查看文末的学习资源~
总而言之,用useEvent给他裹上就是香,就是可以同时达到上面两个效果:
引用不变
拿到恰当的值
这是咋做到的????
说了这么多,我们来看看他这是咋做到的
他大概是这么个形状:(不是源码就长这样的意思嗷)
// (!) Approximate behavior function useEvent(handler) { const handlerRef = useRef(null); // In a real implementation, this would run before layout effects useLayoutEffect(() => { handlerRef.current = handler; }); return useCallback((...args) => { // In a real implementation, this would throw if called during render const fn = handlerRef.current; return fn(...args); }, []); }
先回顾几个Hook相关知识点:
useRef:
useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内持续存在。
这里通过 useRef 保存回调函数handler到handlerRef.current,然后再在 useCallback 中从handlerRef.current来取函数再调用,简单来说就可以跳出循环,打破僵局。并且不出意外的话handler在整个生命周期内持续存在,也就是只有一个引用。
useLayoutEffect
这个useLayoutEffect可能没那么常用,我们来看看这是啥嘞
其函数签名与 useEffect 相同,但它会在所有的 DOM 变更之后同步调用 effect。可以使用它来读取 DOM 布局并同步触发重渲染。在浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新。
useEffect
回顾一下useEffect
默认情况下,effect 将在每轮渲染结束后执行
两者的区别
好了,现在我给你用一个字总结一下两者区别,useLayoutEffect更“快”!这个“块”不是速度更快,而是他“抢跑”了哩。useLayoutEffect是在render之前同步执行,useEffect在render之后异步执行,这里就是保证useLayoutEffect里的回调肯定比useEffect更早前被调用、被执行。
useCallback执行时机
之前就有说道useCallback(fn, deps)相当于useMemo(() => fn, deps)。
文档里是这样说useMemo的:
记住,传入 useMemo 的函数会在渲染期间执行。请不要在这个函数内部执行与渲染无关的操作,诸如副作用这类的操作属于 useEffect 的适用范畴,而不是 useMemo。
也就是他是在render时执行的,也就是保证了赋值handler给handlerRef.current是在前面发生
想要了解一个东西,先了解它的作用。一个useCallback包裹后memoized函数,其中从handlerRef.current中获取函数,并且deps为[],这就表明不会再次更新。
捋一捋????
现在我们重新看下,关于useEvent方法,总结就是:它接收一个回调函数handler作为参数,提供给你一个稳定的函数(始终只有一个引用)并且调用时都是用的你传入的最新的参数...args——比如前面案例中的text,始终都是最新的、正确的、恰当的。再结合一开始的案例,大概流程就是这样:
好的,都已说完了,大家多多学习,有更多的成长帮助。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/128187.html
陷进到处都是啊!本篇文章就说说Hooks使用时存在所谓的闭包陷阱,看看下面代码: functionChat(){ const[text,setText]=useState(''); constonClick=useCallback(()=>{ sendMessage(text); },[]); return<SendButtononClick=...
想必大家都能看得懂的源码 ahooks 整体架构篇,且可以使用插件化机制优雅的封装你的请求hook,现在我们就探讨下ahooks 是怎么解决 React 的闭包问题的?。 React 的闭包问题 先来看一个例子: importReact,{useState,useEffect}from"react"; exportdefault()=>{ const[c...
大家会发现,自从 React v16.8 推出了 Hooks API,前端框架圈并开启了新的逻辑复用的时代,从此无需在意 HOC 的无限套娃导致性能差的问题,同时也解决了 mixin 的可阅读性差的问题。这里也有对于 React 最大的变化是函数式组件可以有自己的状态,扁平化的逻辑组织方式,更加友好地支持 TS 类型声明。 在运用Hooks的时候,除了 React 官方提供的,同时也支持我们...
摘要:更容易将组件的与状态分离。也就是只提供状态处理方法,不会持久化状态。大体思路是利用共享一份数据,作为的数据源。精读带来的约定函数必须以命名开头,因为这样才方便做检查,防止用判断包裹语句。前端精读帮你筛选靠谱的内容。 1 引言 React Hooks 是 React 16.7.0-alpha 版本推出的新特性,想尝试的同学安装此版本即可。 React Hooks 要解决的问题是状态共享,...
摘要:注册方法之后,当执行了当前的,那么挂载正在当前上的方法就会被执行。比如在开始编译之前,就能触发钩子,就用到了当前的。上面都是前置知识,下面通过解读一个源码来巩固下。先看一段简单的源码。,是众多的的一个,官网的解释是编译创建之后,执行插件。 通过解读webpack-manifest-plugin,了解下plugin机制 先简单说一下这个插件的功能,生成一份资源清单的json文件,如下 s...
阅读 485·2023-03-27 18:33
阅读 691·2023-03-26 17:27
阅读 593·2023-03-26 17:14
阅读 562·2023-03-17 21:13
阅读 480·2023-03-17 08:28
阅读 1725·2023-02-27 22:32
阅读 1224·2023-02-27 22:27
阅读 2039·2023-01-20 08:28