react hooks--useCallback

news/2024/9/28 17:08:29/

概述

useCallback缓存的是一个函数,主要用于性能优化!!!

基本用法

如何进行性能的优化呢?

  • useCallback会返回一个函数的 memoized(记忆的) 值;
  • 在依赖不变的情况下,多次定义的时候,返回的值是相同的;

语法:

const memoizedCallback = useCallback(() => {doSomething(a, b);},[a, b],
);
  • 通常使用useCallback的目的是不希望子组件进行多次渲染,并不是为了函数进行缓存;
  • 在使用 React.memo 时,对于对象类型的 props,只会比较引用(浅对比)。
  • 但是,因为组件每次更新都会创建新的 props 值,比如,新的对象、事件处理程序等(函数组件的特性)。
  • 这就导致:React.memo 在处理对象类型的 props 时,会失效(每次的 props 都是新对象)。
  • 但是,我们还是想让 React.memo 在处理对象类型的 props 时,也有效。
  • 为了让 React.memo 处理对象类型的 props 有效,只要在组件更新期间保持对象类型引用相等即可

这时候,就要用到以下两个 Hooks:

  • useCallback Hook:记住函数的引用,在组件每次更新时返回相同引用的函数。
  • useMemo Hook:记住任意数据(数值、对象、函数等),在组件每次更新时返回相同引用的数据【功能之一】

示例:

import {useCallback, useState} from "react";export default function UseCallback() {let [firstName, setFirstName] = useState('张');let [lastName, setLastName] = useState('三');let getFullName = useCallback(() => {return firstName + lastName}, [firstName, lastName])return (<div>姓名:{getFullName()}</div>)
}

缓存了一个函数,可以在组件中使用!!!

演示示例

使用场景:在使用 React.memo 时,为了组件每次更新时都能获取到相同引用的函数,就要用到 useCallback Hook

注意:需要配合 React.memo 高阶函数一起使用

作用:记忆传入的回调函数,这个被记住的回调函数会一直生效,直到依赖项发生改变

解释:

  • 第一个参数:必选,需要被记忆的回调函数。
  • 第二个参数:必选,依赖项数组,用于指定回调函数中依赖(用到)的数据(类似于 useEffect 的第二个参数)。
  • 即使没有依赖,也得传入空数组([]),此时,useCallback 记住的回调函数就会一直生效。
  • 返回值:useCallback 记住的回调函数。
  • useCallback 记住的回调函数会一直生效(或者说会一直返回同一个回调函数),直到依赖项发生改变。
import React, { memo, useState, useCallback, useRef } from 'react'const App = memo(() => {const [count, setCount] = useState(0)const [money, setMoney] = useState(1000)// 初始写法const help = useCallback(() => {setCount(count - 1)}, [count])// 优化写法:useRef--在组件多次渲染时,返回的是同一个值// 这种写法容易陷入闭包陷阱const help = useCallback(() => {setCount(count - 1)}, [])// 推荐优化写法:const countRef = useRef();countRef.current = count;const help = useCallback(() => {setCount(countRef.current - 1)}, [])return (<div><h1>计数器</h1><div>豆豆被打了{count}次</div><div>金钱:{money}</div><button onClick={() => setCount(count + 1)}>打豆豆</button><button onClick={() => setMoney(money + 100)}>加钱</button><hr />{count < 5 ? <DouDou count={count} help={help}></DouDou> : '豆豆被打死了'}</div>)
})export default App

Doudou.jsx

// 子组件
const DouDou = memo(({ count, help }) => {console.log('豆豆组件渲染')return (<div><h3>我是豆豆组件{count}</h3><button onClick={help}>续命</button></div>)
})
export default Doudou

总结:

要配合  memo 不然可能反而会降低性能

  1. 当需要将一个函数传递给子组件,最好使用 useCallback 进行优化,将优化之后的函数,传递给子组件
  2. 当需要将一个函数传递给子组件时,最好使用useCallback进行优化,将优化之后的函数传递给子组件

尽量不要使用 useCallback

我建议在项目中尽量不要用 useCallback,大部分场景下,不仅没有提升性能,反而让代码可读性变的很差。

useCallback 大部分场景没有提升性能

useCallback 可以记住函数,避免函数重复生成,这样函数在传递给子组件时,可以避免子组件重复渲染,提高性能。

基于以上认知,很多人(包括我自己)在写代码时,只要是个函数,都加个 useCallback,是你么?反正我以前是。

但我们要注意,提高性能还必须有另外一个条件,子组件必须使用了 shouldComponentUpdate 或者 来忽略同样的参数重复渲染。

假如 ExpensiveComponent 组件只是一个普通组件,是没有任何用的。比如下面这样:

必须通过 React.memo 包裹 ExpensiveComponent ,才会避免参数不变的情况下的重复渲染,提高性能。

所以,useCallback 是要和 shouldComponentUpdate/React.memo 配套使用的,你用对了吗?当然,我建议一般项目中不用考虑性能优化的问题,也就是不要使用 useCallback 了,除非有个别非常复杂的组件,单独使用即可。

useCallback 让代码可读性变差

我看到过一些代码,使用 useCallback 后,大概长这样:

在上面的代码中,变量依赖一层一层传递,最终要判断具体哪些变量变化会触发 useEffect 执行,是一件很头疼的事情。

我期望不要用 useCallback,直接裸写函数就好:

在 useEffect 存在延迟调用的场景下,可能造成闭包问题,那通过咱们万能的方法就能解决:

对 useCallback 的建议就一句话:没事别用 useCallback。


http://www.ppmy.cn/news/1531034.html

相关文章

暴雨讲堂:算力高速互联催化超节点开启AI新篇章

在2024中国国际北京通信展期间&#xff0c;暴雨副总裁孙辉介绍了暴雨信息在超节点方案的最新突破&#xff0c;彰显了暴雨信息在算力和网络技术上的强大创新能力。 随着人工智能技术的飞速发展&#xff0c;AI大模型的参数规模正以超越摩尔定律的速度急剧扩张。在此背景下&#…

嵌入式开发中学习C++的用处?

这个问题一直有同学在问&#xff0c;其实从我的角度是一定是需要学的&#xff0c;最直接的就是你面试大厂的嵌入式岗位或者相关岗位&#xff0c;最后一定会问c&#xff0c;而很多人是不会的&#xff0c;这就是最大的用处&#xff0c;至于从技术角度考量倒是其次&#xff0c;因为…

828华为云征文|使用Flexus X实例安装宝塔面板教学

目录 一、Flexus X实例简介 1.1 概述 1.2 产品规格 二、切换操作系统 2.1 Huawei Cloud EulerOS 2.0 标准版 2.2 切换镜像 三、部署宝塔面板 3.1 安装宝塔面板 3.2 放通安全组规则 3.3 登录宝塔面板 四、使用感受 4.1 柔性算力随心配 4.2 一直加速一直快 4.3 越用…

Unity 设计模式 之 结构型模式 -【装饰者模式】【外观模式】【享元模式】【代理模式】

Unity 设计模式 之 结构型模式 -【装饰者模式】【外观模式】【享元模式】【代理模式】 目录 Unity 设计模式 之 结构型模式 -【装饰者模式】【外观模式】【享元模式】【代理模式】 一、简单介绍 二、装饰者模式&#xff08;Decorator Pattern&#xff09; 1、什么时候使用装…

Java 编码系列:线程基础与最佳实践

引言 在多任务处理和并发编程中&#xff0c;线程是不可或缺的一部分。Java 提供了丰富的线程管理和并发控制机制&#xff0c;使得开发者可以轻松地实现多线程应用。本文将深入探讨 Java 线程的基础知识&#xff0c;包括 Thread 类、Runnable 接口、Callable 接口以及线程的生命…

智源研究院与百度达成战略合作 共建AI产研协同生态

2024年9月24日&#xff0c;北京智源人工智能研究院&#xff08;简称“智源研究院”&#xff09;与北京百度网讯科技有限公司&#xff08;简称“百度”&#xff09;正式签署战略合作协议&#xff0c;双方将充分发挥互补优势&#xff0c;在大模型等领域展开深度合作&#xff0c;共…

AIGAME背后的强大背景与AI币价值的崛起

AIGAME平台背后汇集了强大的资本和技术支持&#xff0c;凭借蒙特加密产业基金的战略投资和汇旺集团的多元化Web3基础设施建设&#xff0c;AIGAME在全球范围内迅速崛起。平台所使用的Sleepless AI技术&#xff0c;结合区块链与AI的深度融合&#xff0c;赋能AI币&#xff0c;使其…

建造者模式__c#

目录 调用 指挥者 抽象建造者 建造者 定义具体产品 调用 用指挥者指挥建造者建造产品 在指挥者这里组装成产品 namespace _建造者模式 {internal class Program{static void Main(string[] args){Builder buildernew JiangHuaiBuilder();//建造者Director director new…