了解 useDebounce 和 lodash 的 _.debounce:区别与应用场景

841 阅读5分钟

一、什么是防抖(Debounce),为什么要使用防抖?

防抖(Debounce)是一种优化性能的技术,主要用于限制某些频繁触发的操作,以提高性能。它通过延迟执行函数来减少其调用次数,特别是在处理用户输入或滚动事件等高频率触发的场景中非常有用。

为什么要使用防抖?

  1. 提升性能:频繁触发的事件会导致大量不必要的函数调用,从而消耗大量资源。防抖可以减少这些不必要的调用,提高应用的性能。
  2. 防止重复操作:在某些情况下(如表单提交或按钮点击),防止用户快速连续操作导致的重复提交或多次触发。
  3. 提升用户体验:减少页面卡顿或不必要的加载,提供更平滑的交互体验。

二、useDebounce 与 lodash 的 _.debounce 的区别

1. lodash 的 _.debounce

Lodash 是一个流行的 JavaScript 实用工具库,其中的 _.debounce 函数用于创建防抖函数。

使用方法

import React, { useEffect, useCallback } from 'react';
import _ from 'lodash';


function Example() {
const [inputValue, setInputValue] = useState('');

  // 定义防抖函数
  // 使用 useCallback 确保防抖函数的稳定性
  const debouncedPrint = useCallback(
    _.debounce((value) => {
      console.log(value); // 打印输入的值
    }, 500),
    [] // 依赖为空数组,确保该函数只在组件挂载时创建一次
  );

  
const handleInputChange = (event) => {
  const value = event.target.value;
  setInputValue(value); // 更新输入框的值
  debouncedPrint(value); // 调用防抖函数,传入输入的值
};

  return <div>
    <Input
        type="text"
        value={inputValue}
        onChange={handleInputChange}
        placeholder="请输入"
     />
     </div>;
};

export default Example;

2. 自定义 Hook:useDebounce

useDebounce 是一个自定义 Hook,专门为 React 设计,可以更好地与 React 的状态和生命周期钩子配合使用。

使用方法


// 自定义 Hook
import { useEffect, useRef, useCallback } from 'react';

/**
 * 自定义 Hook:useDebounce
 * 用于创建一个防抖函数,只有在指定的延迟时间内没有再次调用时,才会执行传入的函数。
 **/
function useDebounce(fn, delay = 100, dep = []) {
  // 创建一个 ref 对象,初始值包含要防抖的函数和定时器 ID
  const { current } = useRef({ fun: fn, timer: null });

  // 每次传入的函数发生变化时,更新 current.fun
  useEffect(
    function () {
      current.fun = fn;
    },
    // eslint-disable-next-line
    [fn]
  );

  // 返回一个使用 useCallback 包裹的防抖函数
  return useCallback((args) => {
    if (current.timer) {
      clearTimeout(current.timer);
    }
    current.timer = setTimeout(() => {
      current.fun(args);
    }, delay);
    // eslint-disable-next-line
  }, dep); 
}

export default useDebounce;


import React, { useState } from 'react';
import useDebounce from './useDebounce'; 

function MyComponent() {
  const [inputValue, setInputValue] = useState('');

  // 使用自定义的 useDebounce 钩子创建防抖函数
  const debouncedPrint = useDebounce((value) => {
    console.log(value); // 打印输入的值
  }, 500);

  // 处理输入框变化事件
  const handleInputChange = (event) => {
    const value = event.target.value;
    setInputValue(value); // 更新输入框的值
    debouncedPrint(value); // 调用防抖函数,传入输入的值
  };
  return (
    <div>
      <input
        type="text"
        value={inputValue}
        onChange={handleInputChange}
        placeholder="Type something..."
      />
    </div>
  );
}

export default MyComponent;

3. 区别

  • 依赖处理_.debounce 是一个普通的 JavaScript 函数,不会自动处理 React 的依赖关系。每次组件重新渲染时,可能会创建新的防抖函数,导致前一个防抖函数没有正确清理。而 useDebounce 自定义 Hook 能够处理依赖关系,确保只有在依赖变化时才会创建新的防抖函数。
  • 清理机制:使用 _.debounce 时需要手动清理定时器,而 useDebounce 自定义 Hook 可以在组件卸载或依赖变化时自动清理定时器,避免内存泄漏和不必要的调用。
  • **React **:useDebounce 与 React 状态和生命周期钩子能很好的契合,使代码更加简洁和可靠。

三、使用场景及示例

Lodash _.debounce 的使用场景

  1. 非 React 环境:在普通的 JavaScript 项目或其他框架中,Lodash 的 _.debounce 更为常见。
  2. 简单防抖需求:当你需要在某些简单的场景下使用防抖,例如防止用户在短时间内多次点击按钮。

示例:防止按钮多次点击

import React from 'react';
import _ from 'lodash';

const handleClick = _.debounce(() => {
  console.log('Button clicked');
}, 300);

const DebounceButton = () => (
  <button onClick={handleClick}>Click me</button>
);

export default DebounceButton;


import React, { useEffect, useCallback } from 'react';
import _ from 'lodash';


function Example() {
const [inputValue, setInputValue] = useState('');

  // 定义防抖函数
  // 使用 useCallback 确保防抖函数的稳定性
  const debouncedPrint = useCallback(
    _.debounce((value) => {
      console.log(value); // 打印输入的值
    }, 500),
    [] // 依赖为空数组,确保该函数只在组件挂载时创建一次
  );

  
const handleInputChange = (event) => {
  const value = event.target.value;
  setInputValue(value); // 更新输入框的值
  debouncedPrint(value); // 调用防抖函数,传入输入的值
};

  return <div>
    <Input
        type="text"
        value={inputValue}
        onChange={handleInputChange}
        placeholder="请输入"
     />
     </div>;
};

export default Example;

useDebounce 的使用场景

  1. React 项目:在 React 项目中处理防抖时,useDebounce 更加适合,因为它能更好地处理 React 的依赖关系和生命周期。
  2. 复杂的依赖关系:当防抖函数依赖于多个状态时,useDebounce 能够确保这些依赖的变化被正确处理。

示例:防抖 防止用户输入值频繁打印

import React, { useState } from 'react';
import useDebounce from './useDebounce'; 

function MyComponent() {
  const [inputValue, setInputValue] = useState('');

  // 使用自定义的 useDebounce 钩子创建防抖函数
  const debouncedPrint = useDebounce((value) => {
    console.log(value); // 打印输入的值
  }, 500);

  // 处理输入框变化事件
  const handleInputChange = (event) => {
    const value = event.target.value;
    setInputValue(value); // 更新输入框的值
    debouncedPrint(value); // 调用防抖函数,传入输入的值
  };
  return (
    <div>
      <input
        type="text"
        value={inputValue}
        onChange={handleInputChange}
        placeholder="Type something..."
      />
    </div>
  );
}

export default MyComponent;


结论

在 React 项目中,选择使用 useDebounce 自定义 Hook 通常会带来更好的开发体验和更稳定的代码。而在非 React 项目或简单的防抖需求中,Lodash 的 _.debounce 则是一个更直接的选择。根据具体的使用场景和需求选择合适的防抖实现方式,可以更好地提升应用的性能和用户体验。