【React】useCallback 使用的说明

文章目录

用了两年多的react,今天抽空写点小内容

useCallback的优缺点

缓存了每次渲染时候 inline callback的实例

优点

关键点:利用memoize减少无效的re-render,通常配合shouldComponentUpdate 或者 React.memo 起到减少不必要渲染的目的

  1. 性能优化:useCallback可以帮助避免每次渲染的时候创建新的函数实例。这对于将函数作为props传递给子组件的时候特别有用,因为子组件可以使用React.memo 来进行浅比较,从而避免不必要的重新渲染
  2. 依赖性控制: useCallback 接受一个依赖数组作为第二个参数,使得你可以明确指定哪些变量的变化应该导致函数重新创建。这有助于精确控制依赖,避免不必要的重新计算。

缺点

  1. 过度使用可能导致性能问题:useCallback可能会阻止某些优化(如内联)
  2. 增加复杂性:在简单组件中,使用useCallback 可能会显得过于繁琐,因此优先考虑组件的复杂性和性能需求,权衡是否使用useCallback
  3. 可能引入bug:如果依赖数组设置不当,导致函数被错误缓存

JavaScript 的内联优化

  1. 内联优化:内联指的是 将函数调用代码直接插入到调用处,而不是通过函数调用方式执行,这样可以减少函数调用的开销,提高性能。当使用useCallback 包裹一个函数时候,React 可能无法在一些情况进行内联,因为useCallback返回的是同一个函数实例,而不是新的函数

    const memoizedCallback = useCallback(() => {
    // function body
    }, [/* dependencies */]);

    // 内联优化可能受到影响
    <SomeComponent onClick={memoizedCallback} />

  2. 对象缓存:内联也与对象的创建和缓存有关。如果一个函数内部创建了对象,并且该函数被useCallback缓存,那么对象可能被缓存在在闭包中,导致无法及时被垃圾回收。这可能会在长时间运行的应用中引起内存泄露问题

    const memoizedCallback = useCallback(() => {
    const obj = { key: 'value' };
    // 使用 obj
    }, [/* dependencies */]);

    // obj 可能无法及时被垃圾回收

为了确保在不再需要时能够及时释放对象并触发垃圾回收,你可以采取以下步骤:

Javascript 复制代码
import { useCallback, useEffect, useRef } from 'react';

const MyComponent = () => {
  const memoizedObject = useRef(null);

  memoizedObject.current = useCallback(() => {
    const obj = { key: 'value' };
    // 使用 obj
    return obj;
  }, [/* dependencies */]);

  // ...

  // 如果 memoizedObject 不再被使用,设置为 null 或者清除引用
  useEffect(() => {
    return () => {
      // 清除对 memoizedObject 的引用
      // 这样,在组件卸载或 memoizedObject 不再使用时,可以及时触发垃圾回收
      memoizedObject.current = null;
    };
  }, []);

  // ...
};

在这个例子中,我们使用 useEffect 来监听组件的生命周期,并在组件即将卸载时执行清理操作。通过将 memoizedObject.current 设置为 null 或清除引用,我们告诉垃圾回收器这个对象不再被需要。这有助于确保在组件卸载或不再需要时能够及时释放对象并触发垃圾回收。

请注意,这里使用了 memoizedObject.current,因为在 React Hooks 中,我们经常使用 useRef 来保存可变的值,并确保在组件重新渲染时保持其稳定性。如果你使用 useRef 来保存 memoizedObject,你可以在 useEffect 中设置 memoizedObject.current 为 null 或清除引用。

使用场景

  1. 函数被 useEffect 内部所引用了,但为了避免频繁的useEffect的频繁调用,可以选择包一下;
  2. 需要保存一个函数闭包结果,如配合 debounce、throttle使用;
  3. useCallback包裹的函数,但某个依赖项变化时,引用这个函数的所有 useEffect 都得重新执行一下;

最后分享一个外链:Day383:说下 React 的 useEffect、useCallback、useMemo

相关推荐
Ten peaches23 分钟前
Selenium-Java版(环境安装)
java·前端·selenium·自动化
心.c35 分钟前
vue3大事件项目
前端·javascript·vue.js
姜 萌@cnblogs1 小时前
【实战】深入浅出 Rust 并发:RwLock 与 Mutex 在 Tauri 项目中的实践
前端·ai·rust·tauri
蓝天白云下遛狗1 小时前
google-Chrome常用插件
前端·chrome
多多*1 小时前
Spring之Bean的初始化 Bean的生命周期 全站式解析
java·开发语言·前端·数据库·后端·spring·servlet
linweidong2 小时前
在企业级应用中,你如何构建一个全面的前端测试策略,包括单元测试、集成测试、端到端测试
前端·selenium·单元测试·集成测试·前端面试·mocha·前端面经
满怀10152 小时前
【HTML 全栈进阶】从语义化到现代 Web 开发实战
前端·html
东锋1.32 小时前
前端动画库 Anime.js 的V4 版本,兼容 Vue、React
前端·javascript·vue.js
满怀10152 小时前
【Flask全栈开发指南】从零构建企业级Web应用
前端·python·flask·后端开发·全栈开发
小杨升级打怪中3 小时前
前端面经-webpack篇--定义、配置、构建流程、 Loader、Tree Shaking、懒加载与预加载、代码分割、 Plugin 机制
前端·webpack·node.js