const memoizedFunc = useCallback(function useEffectDependentFunction(){
return someValue;
}, [useEffectDependentFunction_dependency])
// useEffectDependentFunction will be stored in the same memory location under the name memoizedFunc untill useEffectDependentFunction_dependency is not changed.
useEffect(()=>{
//do something
}, [memoizedFunc]}
const memoizedValue = useMemo(()=>function useEffectDependentValueYieldingFunction(){
//some calculation
return someValue;
}, [useEffectDependentValueYieldingFunction_dependency])
// the value returned from the useEffectDependentValueYieldingFunction will be stored in the same memory location under the name memoizedValue untill useEffectDependentValueYieldingFunction_dependency is not changed.
useEffect(()=>{
//do something
}, [memoizedValue]}
7条答案
按热度按时间cigdeys31#
TL;DR;
useMemo
用于存储函数调用之间和渲染之间的计算结果useCallback
是在渲染之间记忆回调本身(引用相等)useRef
用于保留渲染之间的数据(更新不会触发重新渲染)useState
用于保留渲染之间的数据(更新将触发重新渲染)长版本:
useMemo
侧重于避免繁重的计算。useCallback
关注的是另一件事:它修复了onClick={() => { doSomething(...); }
等内联事件处理程序导致PureComponent
子级重新呈现时的性能问题(因为每次引用的函数表达式都不同)也就是说,
useCallback
更接近于useRef
,而不是存储计算结果的方式。看了看文件,我同意这看起来很混乱。
useCallback
将返回回调的记忆版本,该版本仅在其中一个输入发生更改时才发生更改。这在 * 将回调传递给依赖引用相等的优化子组件以防止不必要的呈现时 *(例如shouldComponentUpdate)非常有用。示例
假设我们有一个基于
PureComponent
的子<Pure />
,它只会在其props
发生变化时重新呈现。此代码在每次重新呈现父级时重新呈现子级,因为每次引用的内联函数都不同:
我们可以借助
useCallback
来处理这个问题:但是一旦
a
被修改,我们发现我们创建的onPureChange
处理函数--React为我们记住了--仍然指向旧的a
值!我们得到的是一个bug而不是性能问题!这是因为onPureChange
使用闭包来访问a
变量,这是在声明onPureChange
时捕获的。要解决此问题,我们需要让React知道在哪里删除onPureChange
并重新创建/记住(memoize)指向正确数据的新版本。我们通过在'useCallback:现在,如果
a
发生了变化,React会重新渲染<Parent>
。在重新渲染过程中,它会发现onPureChange
的依赖关系不同,因此需要重新创建/记忆一个新版本的回调。这将传递给<Pure>
,由于它的引用不同,<Pure>
也会被重新渲染。最后,一切都正常了!注意:不仅仅对于
PureComponent
/React.memo
,当在useEffect
中使用某个对象作为依赖项时,引用相等性可能是关键。vhmi4jdf2#
useMemo
和useCallback
使用记忆。我喜欢把回忆当作记忆的东西。
虽然
useMemo
和useCallback
在依赖关系改变之前都记得渲染之间的一些东西,但区别只是它们记得的东西。useMemo
将记住您的函数返回的值。useCallback
将记住**您实际函数。来源:What is the difference between useMemo and useCallback?
nlejzf6q3#
useCallback
与useMemo
的单行程序:useCallback(fn, deps)
等同于useMemo(() => fn, deps)
。使用
useCallback
可以记忆函数,而useMemo
可以记忆任何计算值:(1)
将返回fn
的记忆版本--只要dep
相同,多个渲染器之间的引用相同。但是,* 每次 * 调用 *memoFn
时,复杂的计算都会重新开始。(2)
将在每次dep
改变时调用fn
,并记住它的 * 返回值 *(这里是42
),然后将其存储在memoFnReturn
中。第一次
um6iljoc4#
每次调用时,您都会调用记忆回调:
这就是
useCallback
的计数上升的原因。然而函数从未改变,它从未*****创建****新的回调,它总是一样的。这意味着useCallback
正确地完成了它的工作。让我们在代码中做一些更改来验证这一点。让我们创建一个全局变量
lastComputedCallback
,它将跟踪新如果返回了一个新的函数,这意味着useCallback
只是“再次执行”。因此,当它再次执行时,我们将调用expensiveCalc('useCallback')
,因为这是计算useCallback
是否工作的方法。我在下面的代码中做了这件事,现在很明显useCallback
正在按预期进行记忆。如果你想看到
useCallback
每次都重新创建函数,那么取消数组中传递second
的行的注解,你会看到它重新创建函数。第一次
useCallback
的好处是返回的函数是相同的,所以react不是每次都对元素执行removeEventListener
'ing和addEventListener
ing,除非computedCallback
发生变化。并且computedCallback
只在变量发生变化时才发生变化。因此react只会对addEventListener
执行一次。问得好,回答了我学到了很多。
h6my8fg25#
useCallback()
和useMemo()
几乎相同,但useCallback
将函数引用保存在内存中,并在第二次渲染时检查是否相同。如果相同,则返回上次保存的函数,而不重新创建它。如果发生更改,则返回新函数,并将其替换为内存中的旧函数,以便将来渲染。useMemo
以同样的方式工作,但它不能保存您的函数,只能保存计算或返回值。在每次渲染时,useMemo
都会检查该值。如果函数的返回值与第二次渲染时的值相同,则它将返回相同的值,而不重新计算函数值;如果第二次渲染时的值与第一次渲染时的值不同,则它将返回相同的值第二次渲染时,它将调用该函数并返回新值,然后将其存储以供将来渲染。注意:当您需要使用这些挂接时必须小心。不必要地使用这些挂接可能会使您的应用程序性能变差,因为它们会占用内存。请确保如果您的组件多次重新呈现,并且计算量很大,则最好使用这些挂接。
rkkpypqq6#
在useMemo和useCallback中,钩子都接受一个函数和一个依赖项数组。
用例:用于大量缓存计算值。
用例:用于缓存API调用方法,只能由用户的action调用。
干杯!
gstyhher7#
在详细了解useCallback和useMemo钩子之前,让我们先了解一下React如何比较在useEffect的依赖项数组中添加的值。
React通过使用Object.is(),即通过引用相等性来比较这些值。通常,对于基元数据类型,基于其值来比较值,如果它们相等,则认为它们相似,否则将它们视为不同,而对于非基元数据类型(对象、数组或函数),基于存储器位置引用来比较值,如果这些值共享相同的存储器位置,则它们被认为是相似的,否则被视为不同的(即使两个对象具有相同的属性,如果存储器位置引用不同,则它们被视为不相同)。
现在,如果useEffect的依赖关系依赖于基元数据类型值,那么就没有问题,因为我们已经看到React将如何比较它们。问题是非基元数据类型值,因为我们已经知道,对于相同的两个对象,内存位置引用相同,以便将它们视为相似。
现在问题来了,我们如何使两个相同的非原始数据值被认为是相似的。是的,唯一可能的答案是使它们共享相同的内存位置引用,现在我们实际上是如何做到这一点的呢?2这里有useCallback和useMemo钩子,如果渲染之间的值没有变化的话,它们可以帮助在相同的内存引用下存储非原始数据类型的值。
现在,useEffect可以比较它的非原语依赖关系,并且只有在依赖关系中有实际变化时才运行。
如果函数用作useEffect中的依赖项,则该函数可被 Package 在返回记忆函数的useCallback中,即,返回存储在相同内存引用下的相同函数定义,除非函数依赖项未更改。
如果某个数组或对象或从函数中经过计算后获得的值将被用作useEffect中的依赖项,那么,涉及计算的函数可以被 Package 在useMemo中,useMemo根据用例返回记忆的数组或对象或值,与useCallback不同,它不会返回函数本身,而是返回函数的计算值。
就这样了
上面解释的场景是有效使用useCallback和useMemo的用例之一。