当前位置: 首页 > 知识库问答 >
问题:

react.js - 关于React useCallback使用的问题?

司寇凯
2023-12-18

React中的useCallback

下面的代码中Com是父组件,Button是子组件,子组件接收父组件的count2setCount2,子组件中使用了memo(Button)导出

function Com() {    const [count1, setCount1] = useState(0)    const [count2, setCount2] = useState(0)    const handleClick1 = () => {setCount1(i => i + 1)}    const handleClick2 = () => {setCount2(i => i + 1)}    // const callbackSetCount2 = useCallback(() => {    //     setCount2(i => i + 1)    // }, [count2])    console.log("$$ ComA render")    return (        <div className="addBorder">            <h1>this is ComA</h1>            <p>{count1}</p>            <button handleClick={() => setCount1(i => i + 1)}>count1 ++</button>            <p>count2</p>            <Button handleClick={handleClick2}>{count2}</Button>        </div>    )}

子组件Button

function Button({ handleClick, children }) {    console.log(`$$ Rendering button` + children)    return (        <div className="addBorder">            <p>this is Button.jsx</p>            <button onClick={handleClick}>{children}</button>        </div>    )}export default memo(Button)

在上面的代码中,如果点击count1++的按钮(不使用useCallback),父组件会重新渲染,但是子组件也会刷新,然而子组件中的count2依赖没有变化,所以只能是handleClick2函数变化了,这只能是因为父组件重新渲染导致了const handleClick2 = () => {setCount2(i => i + 1)}这一行重新运行。
所以我们需要使用useCallback来将handleClick2函数缓存,不会因为重新渲染而导致没有必要的刷新,这样做之后,点击count1++的按钮也不会导致子组件刷新了。
这是我对上面代码以及重新渲染机制以及useCallback的理解,这样理解对吗?

希望理解useCallback以及setState之后的更新机制,谢谢各位大佬了

共有3个答案

别永年
2023-12-18

useCallback 的核心作用就是保持函数的引用恒定,从而避免函数作为组件参数时,引用变化导致的组件重复渲染,从而影响性能。以题主的代码为例:

1、每次函数组件更新,都会重新创建一个新的函数,导致 handleClick2 的引用变更:

const handleClick2 = () => {setCount2(i => i + 1)}

2、使用 useCallback 缓存首次创建的函数,每次函数组件更新,都会返回之前函数的引用(保证引用恒定):

const callbackSetCount2 = useCallback(() => {    setCount2(i => i + 1)}, [])

希望对你有所帮助!

苏洛城
2023-12-18

因为

(()=>{}) !== (()=>{})

所以当prop中有函数作为依赖项的时候,React.memo会失去效果,无论你做了父组件啥都会触发更新

所以用useCallBack去封装一次函数就可以达到你要的效果

同理在useMemo也是一样的

所以在新手学习React-hook的时候官网都会强烈建议打开eslint-plugin-react-hooks

鲁鸿
2023-12-18

你的理解基本是正确的。useCallback是React的一个Hook,它返回一个记忆化的回调函数。在组件的多次渲染之间,useCallback会保持函数引用的一致性。所以,如果你在父组件中使用useCallback封装了handleClick2,那么在父组件的多次渲染中,handleClick2的引用始终保持不变。

当你在父组件中调用setCount1时,父组件会因为状态变化而重新渲染。但由于handleClick2useCallback封装了,它的引用始终保持不变,所以子组件不会因为父组件的重新渲染而重新渲染。这样,你就可以避免子组件的不必要刷新。

另外,关于React的重新渲染机制,需要注意的是,React的重新渲染并不意味着整个组件完全重新渲染。实际上,React会进行有效的比较,只更新改变的部分。但是,如果你在一个组件中改变了状态或props,那么该组件以及所有子组件都将被重新渲染。

希望这个答案对你有所帮助!如果你还有其他问题,欢迎继续提问。

 类似资料:
  • 我用亚马逊云的Lambda函数,通过langChain调用OpenAI API。我把OPENAI_API_KEY存在了Lambda函数的环境变量里了。神奇的是,在创建new ChatOpenAI()实例的时候没有传入OPENAI_API_KEY,还是可以获取到正确的返回值。这是为什么?

  • 用的TypeScript。 我定义了一个函数组件:MyView: 可以正常使用: 为了看起简洁点,我将 MyView 稍微修改了一下: 这个时候调用的地方就报错了: 报错信息: Type '{ children: Element; }' is not assignable to type 'IntrinsicAttributes & ReactNode'. Type '{ children: El

  • 我把 items 换成 ccc 为什么就提示有问题?直接就挂了?

  • 本文向大家介绍关于使用js算总价的问题,包括了关于使用js算总价的问题的使用技巧和注意事项,需要的朋友参考一下 昨天对接数据,发现有个商品总价需要计算,商品数量不定,商品价格不定,商品种类不定,有点蒙,想来想去想找到点简单的写法也没想到,最后提供一种简单的思路吧。 商品数量,商品价格先建立两个数组; 之后在新建一个数组放单个商品总价的数组; 之后获取到所有的商品数量,商品价格放入数组,两个数组进行

  • 所以我安装了pip-install-django-haystack或者我的项目virtualenv文件夹中的任何命令,我也安装了solr,但是现在我对该怎么做有些困惑。 我一直收到一个错误,说solr后端需要安装pysolr?我不知道我在哪里运行这个命令?“/manage.py build\u solr\u schema” 我一直试图参考《草垛指南》,但它有点模糊。请帮帮我!!谢谢

  • 问题内容: 常量INADDR_ANY是所谓的IPv4通配符地址。通配符IP地址对于在多宿主主机上绑定Internet域套接字的应用程序很有用。如果多宿主主机上的应用程序将套接字仅绑定到其主机的IP地址之一,则该套接字只能接收发送到该IP地址的UDP数据报或TCP连接请求。但是,我们通常希望多宿主主机上的应用程序能够接收指定主机IP地址的数据报或连接请求,并将套接字绑定到通配符IP地址可以实现这一点