学习React-18-useCallBack

useCallback 简介

useCallback 是 React 中的一个 Hook,用于优化性能,避免在每次渲染时重新创建函数。它通过缓存函数实例,仅在依赖项变化时重新创建函数。适用于需要将函数作为 props 传递给子组件或依赖函数引用的场景。

基本语法

javascript 复制代码
const memoizedCallback = useCallback(
  () => {
    // 函数逻辑
  },
  [dependencies] // 依赖项数组
);
参数
  • callback 回调函数
  • dependencies 依赖项,当依赖项发生变化时会调用回调函数
返回值
  • 返回一个记忆化的回调函数,可以减少函数的创建次数,提高性能。

使用场景

避免不必要的子组件渲染

当父组件传递回调函数给子组件时,如果父组件重新渲染,子组件也会重新渲染(即使 props 未变化)。使用 useCallback 可以缓存函数,避免子组件不必要的渲染。

依赖函数引用的优化

在 useEffect 或其他 Hook 中,如果依赖项包含函数,使用 useCallback 可以避免因函数引用变化而触发不必要的副作用。

小栗子

javascript 复制代码
import React, { useState, useCallback } from 'react'
// 创建WeakMap用于记录加载几次
const map = new WeakMap()
let renderCount = 1
export const TestCallBack: React.FC = () => {

    const [count, setCount] = useState('')
    
    
    const changeCount = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
        setCount(e.target.value)
    
    }, [])

    if(!map.has(changeCount)) {
        map.set(changeCount, renderCount++)
    }
    console.log(`renderCount: ${map.get(changeCount)}`)
    return (
        <div>
            <h3>测试UseTextCallBack</h3>
            <input type="text" onChange={changeCount} />
        </div>
    )
}

export default TestCallBack

效果演示:

中栗子

ts 复制代码
import React, { useState, useCallback, useMemo } from 'react'


interface ChildData {
    btnName: string
    btnClick: () => void
}

const Child: React.FC<ChildData> = React.memo((props) => {
    console.log('子组件渲染了')

    const { btnName, btnClick } = props
    return (
        <div>
            <button onClick={btnClick}>{btnName}</button>
        </div>
    )
})

export const TestCallBack: React.FC = () => {

    const [count, setCount] = useState('')
    
    // const btnClick = () => {
    //     console.log('点击了')
    // }
    const btnClick = useCallback(() => {
        console.log('点击了')
    }, [])

    return (
        <div>
            <h3>测试UseTextCallBack</h3>
            <input value={count} onChange={(e) => setCount(e.target.value)} />
            <Child btnName="点击" btnClick={btnClick} />
        </div>
    )
}

export default TestCallBack

效果如下:

这里可直观的看到在没有使用useCallBack之前,即使使用了useMemo,当输入框的state变化时,子组件还是重新渲染。所以这是为什么呢?原因很简单,在你每次输入的时候,浏览器都会将App重新渲染,所以参数的函数内存地址也会发生变化,这就导致浏览器认为这是一个新的,所以就重新渲染。

注意事项

  1. 依赖项数组

    确保所有依赖项(如 state、props 或其他变量)都正确添加到依赖项数组中,否则可能导致闭包问题或过时的值。

  2. 过度优化的风险

    并非所有函数都需要使用 useCallback。过度使用可能会增加代码复杂度,反而降低性能。仅在必要时使用。

  3. 与 React.memo 结合使用
    useCallback 通常与 React.memo 一起使用,避免子组件因函数引用变化而重新渲染。

性能对比

未使用 useCallback 时,每次父组件渲染都会创建新的函数实例,导致子组件重新渲染。使用后,函数实例被缓存,子组件仅在依赖项变化时重新渲染。

总结

useCallback 是 React 性能优化的重要工具,适用于需要缓存函数引用的场景。合理使用可以减少不必要的渲染,提升应用性能。
useCallback并不是为了阻止函数的重新创建,而是通过依赖项来决定是否返回新的函数或旧的函数,从而在依赖项不变的情况下确保函数的地址不变。

相关推荐
福兮说8 小时前
前端下载大文件,点了按钮半天没反应:fetch + blob 的三个问题和三种替代写法
前端·javascript·性能优化·文件下载
GreenTea8 小时前
我把 Agent 的 while 循环拆掉了:一种你可能没想到的 Agent 架构
前端·后端·架构
科技观察哨9 小时前
六足平台选型与纳米定位系统集成:HEB-640六自由度位移台在半导体光刻对准中的参数边界与国产替代评估
前端·人工智能
落魄大学生之流水线上谋生计9 小时前
Remotion:用 React 写视频,让代码成为剪辑师
react.js
差不多的周周9 小时前
《骨架上下文:基于零镜头骨架的动作识别的骨架侧上下文提示学习》论文核心部分详解
学习
niucloud-admin9 小时前
JAVA V6 多商户商城 开发文档——web前端
前端
颜进强9 小时前
16 · NestJS LifecycleEvents 生命周期事件:五个钩子、三条边界,和 rag-server 的优雅停机
前端·后端·ai编程
Century_Dragon10 小时前
从挂图到VR:汽修专业的一堂新能源原理课可以怎么上~
学习
知识分享小能手11 小时前
C++ 学习教程,从入门到精通,C++对象和类 — 详细知识点总结(10)
开发语言·c++·学习
今年下半年11 小时前
【VUE】整合腾讯地图、自定义区域边界、村委名称及资产统计(放大显示资产点位)
前端·javascript·vue.js