当前位置: 首页 > news >正文

react hooks--useCallback

概述

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.lryc.cn/news/444591.html

相关文章:

  • 828华为云征文|华为云Flexus X实例docker部署最新Appsmith社区版,搭建自己的低代码平台
  • webservice cxf框架 jaxrs jaxws spring整合 接口测试方法 wsdl报文详解 springboot整合 拦截器 复杂参数类型
  • 2024AI做PPT软件如何重塑演示文稿的创作
  • 谷神后端list转map
  • Java集合(Map篇)
  • VUE3配置路由(超级详细)
  • 【笔记】机器学习算法在异常网络流量监测中的应用
  • 江协科技STM32学习- P15 TIM输出比较
  • 使用python-pptx批量删除备注:清除PPT文档中的所有备注信息
  • RTX NVIDIA 3090卡配置对应pytorch,CUDA版本,NVIDIA驱动过程及问题整理
  • 【Verilog学习日常】—牛客网刷题—Verilog快速入门—VL21
  • 【深度】为GPT-5而生的「草莓」模型!从快思考—慢思考到Self-play RL的强化学习框架
  • 【编程底层原理】Java常用读写锁的使用和原理
  • 自恢复保险丝SMD1206B005TF在电路中起什么作用
  • 2024年躺平,花大半年的时间,就弄了这一件事儿:《C++面试真题宝典》
  • PHP基础语法讲解
  • 【论文速看】DL最新进展20240923-长尾综述、人脸防伪、图像分割
  • device靶机详解
  • 十四、SOA(在企业中的应用场景)
  • 单片机与PIC的区别:多方面对比
  • python新手的五个练习题
  • Go语言并发编程之sync包详解
  • 函数题 6-10 阶乘计算升级版【PAT】
  • java项目之基于springboot的医院资源管理系统源码
  • Docker命令全解析:掌握容器化技术的基石
  • 2024.9.19
  • “跨链桥“的危害
  • GO CronGin
  • 手机在网状态查询接口如何用C#进行调用?
  • Java面向对象特性与泛型:深入理解与应用