一、什么是防抖(Debounce),为什么要使用防抖?
防抖(Debounce)是一种优化性能的技术,主要用于限制某些频繁触发的操作,以提高性能。它通过延迟执行函数来减少其调用次数,特别是在处理用户输入或滚动事件等高频率触发的场景中非常有用。
为什么要使用防抖?
- 提升性能:频繁触发的事件会导致大量不必要的函数调用,从而消耗大量资源。防抖可以减少这些不必要的调用,提高应用的性能。
- 防止重复操作:在某些情况下(如表单提交或按钮点击),防止用户快速连续操作导致的重复提交或多次触发。
- 提升用户体验:减少页面卡顿或不必要的加载,提供更平滑的交互体验。
二、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 的使用场景
- 非 React 环境:在普通的 JavaScript 项目或其他框架中,Lodash 的
_.debounce
更为常见。 - 简单防抖需求:当你需要在某些简单的场景下使用防抖,例如防止用户在短时间内多次点击按钮。
示例:防止按钮多次点击
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 的使用场景
- React 项目:在 React 项目中处理防抖时,
useDebounce
更加适合,因为它能更好地处理 React 的依赖关系和生命周期。 - 复杂的依赖关系:当防抖函数依赖于多个状态时,
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
则是一个更直接的选择。根据具体的使用场景和需求选择合适的防抖实现方式,可以更好地提升应用的性能和用户体验。