了解如何驯服React的useCallback挂钩

自学咖网努力为各位打造免费分享知识与教程网站

React.js这几年流行已经不是什么秘密了。它现在是互联网上许多最杰出参与者的首选JavaScript库,包括脸书和WhatsApp。

其兴起的一个主要原因是16.8版本中钩子的引入。React挂钩允许您在不编写类组件的情况下利用React函数。现在,带钩子的功能组件已经成为开发者使用React的首选结构。

在这篇博文中,我们将深入探讨回调使用的一个具体钩子——因为它涉及到函数式编程的一个基本部分,即记忆。您将确切地知道如何以及何时使用useCallback钩子,并充分利用它的性能增强。

什么是备忘录?

渲染和反应

React useCallback的性能优势

React useCallback的缺点

使用回调示例做出反应

什么是备忘录?

记忆化是指一个复杂函数存储它的输出,以便下次可以用相同的输入调用它。它类似于缓存,但在本地级别。它可以跳过任何复杂的计算,更快地返回输出,因为它已经被计算过了。

这将对内存分配和性能产生重大影响,这种压力就是useCallback钩子的目的。

使用回调和使用备忘录进行反应

在这一点上,值得一提的是,useCallback与另一个名为useMemo的钩子很好地配对了。我们将讨论它们,但是在本文中,我们将集中讨论使用useCallback的主题。

区别在于useMemo返回一个内存值,而useCallback返回一个内存函数。这意味着useMemo用于存储计算值,而useCallback返回一个函数,您可以在以后调用它。

这些钩子会给你一个缓存的版本,除非它们的依赖关系(比如状态或者道具)发生了变化。

让我们来看看这两个函数的作用:

import { useMemo, useCallback } from ‘react’const values = [3, 9, 6, 4, 2, 1]// This will always return the same value, a sorted array. Once the values array changes then this will recompute.const memoizedValue = useMemo(() => values.sort(), [values])// This will give me back a function that can be called later on. It will always return the same result unless the values array is modified.const memoizedFunction = useCallback(() => values.sort(), [values])

上面的代码片段是一个人工示例,但是显示了两个回调之间的区别:

MemoizedValue将成为一个数组[1,2,3,4,6,9]。只要values变量保持不变,memoizedValue将保持不变,并且永远不会重新计算。

MemoizedFunction将是一个返回数组[1,2,3,4,6,9]的函数。

这两个回调的优点是,它们将被缓存并一直存在,直到依赖数组发生变化。这意味着在渲染时,它们不会被垃圾收集。

和渲染反应。

为什么记忆在反应中很重要?

它与React如何渲染组件有关。React使用存储在内存中的虚拟DOM来比较数据并决定更新什么。

虚拟DOM有助于提高性能并保持应用程序快速运行。默认情况下,如果组件中的任何值发生变化,整个组件都将重新呈现。这使得React对用户输入做出“反应”,并允许在不重新加载页面的情况下更新屏幕。

您不想渲染组件,因为更改不会影响它。这是你用useCallback和useMemo就能记住的地方。

当React重新呈现您的组件时,它也会重新创建您在组件中声明的函数。

注意,当比较一个函数与另一个函数的相等性时,它们总是假的。因为一个函数也是一个对象,它只会等于它自己:

// these variables contain the exact same function but they are not equalconst hello = () => console.log(‘Hello Matt’)const hello2 = () => console.log(‘Hello Matt’)hello === hello2 // falsehello === hello // true

换句话说,当React重新呈现组件时,它会将组件中声明的任何函数视为新函数。

这在大多数情况下没问题,简单的函数容易计算,不会影响性能。但其他时候,当你不希望这个特性被当作新特性时,你可以依靠useCallback来帮助你。

您可能在想,“什么时候我不希望一个函数被当作一个新函数?”在某些情况下,使用回调更有意义:

将您的功能传递给另一个同样被记忆的组件(使用备忘录)

你的函数需要记住一个内部状态。

你的函数依赖于另一个钩子,比如useEffect

React useCallback的性能优势

如果使用得当,useCallback可以帮助加快应用程序的速度,并防止组件在不需要时被重新呈现。

例如,假设您有一个获取大量数据并负责以图表或图形的形式显示数据的组件,如下所示:

自学咖网努力为各位打造免费分享知识与教程网站

使用React组件生成的条形图

假设重新呈现了数据可视化组件的父组件,但是更改后的属性或状态不会影响该组件。在这种情况下,您可能不希望或不需要重新渲染它并重新获取所有数据。避免这种重新渲染和重新采集可以节省用户的带宽,并提供更流畅的用户体验。

React useCallback的缺点

虽然这个钩子可以帮助你提高性能,但是它也有缺点。在使用useCallback(和useMemo)之前,需要考虑以下几点:

垃圾回收:React会丢弃其他没有记住的函数来释放内存。

内存分配:类似于垃圾回收,内存函数越多,需要的内存就越多。此外,每次使用这些回调时,React中都有一堆代码需要使用更多的内存来为您提供缓存的输出。

复杂性:当你开始在这些钩子中包装函数时,你将立即增加代码的复杂性。现在我们需要更多地了解为什么使用这些钩子,并确认它们的使用是正确的。

意识到这些陷阱可以让你免去磕磕绊绊的头痛。当考虑使用useCallback时,要确保性能优势大于劣势。

使用回调示例做出反应

下面是一个带有按钮组件和计数器组件的简单设置。计数器有两种状态,并呈现两个按钮组件,每个按钮组件将更新计数器组件状态的一个单独部分。

按钮组件有两个属性:handleClick和name。每次呈现按钮时,它都会登录到控制台。

import { useCallback, useState } from ‘react’const Button = ({handleClick, name}) => {console.log(`${name} rendered`)return {name}}const Counter = () => {console.log(‘counter rendered’)const [countOne, setCountOne] = useState(0)const [countTwo, setCountTwo] = useState(0)return ({countOne} {countTwo} setCountOne(countOne + 1)} name=”button1″ /> setCountTwo(countTwo + 1)} name=”button1″ />)}

在本例中,无论何时单击任何按钮,您都会在控制台中看到:

// counter rendered// button1 rendered// button2 rendered

现在,如果我们将useCallback应用于handleClick函数,并将按钮包装在React.memo中,我们可以看到useCallback为我们提供了什么。React.memo类似于useMemo,允许我们记忆一个组件。

import { useCallback, useState } from ‘react’const Button = React.memo(({handleClick, name}) => {console.log(`${name} rendered`)return {name}})const Counter = () => {console.log(‘counter rendered’)const [countOne, setCountOne] = useState(0)const [countTwo, setCountTwo] = useState(0)const memoizedSetCountOne = useCallback(() => setCountOne(countOne + 1), [countOne)const memoizedSetCountTwo = useCallback(() => setCountTwo(countTwo + 1), [countTwo])return ({countOne} {countTwo})}

现在,当我们单击任何按钮时,我们只能看到我们单击以登录控制台的按钮:

// counter rendered// button1 rendered// counter rendered// button2 rendered

我们对按钮组件应用了记忆化,传递给它的属性值被认为是相等的。两个handleClick函数被缓存,并将被React视为同一个函数,直到依赖数组中的项的值发生变化(例如countOne、countTwo)。

总结

虽然useCallback和useMemo很酷,但是记住它们有特定的用例——你不应该用这些钩子包装每个函数。如果函数在计算上很复杂,那么传递给内存组件的另一个钩子或prop的依赖关系就是一个很好的指示,您可能希望获得useCallback。

我们希望这篇文章可以帮助你了解这个高级的React函数,帮助你在使用函数式编程的过程中获得更多的信心!

hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » 了解如何驯服React的useCallback挂钩