Project Icon

use-debounce

轻量级 React 防抖库 优化频繁操作

use-debounce 是一个轻量级 React 防抖库,提供简单 API 实现值和回调函数防抖。支持服务端渲染,兼容 underscore/lodash,具备取消和最大等待时间等功能。该库体积小于 1KB,适用于优化 React 应用中的频繁操作。通过防抖机制,可减少不必要的函数调用,提高应用响应速度,有效优化用户输入、滚动等操作,提升应用性能。

useDebounce、useDebouncedCallback 和 useThrottledCallback

无痛实现防抖的 React 库!

  • 体积小巧,小于 1 KB
  • 与 underscore / lodash 实现兼容 — 一次学习,随处使用
  • 支持服务器端渲染!

特性

安装

yarn add use-debounce
# 或
npm i use-debounce --save

复制粘贴指南:

use-debounce

简单用法:https://codesandbox.io/s/kx75xzyrq7

防抖 HTTP 请求:https://codesandbox.io/s/rr40wnropq

leading 参数的防抖 HTTP 请求:https://codesandbox.io/s/cache-example-with-areas-and-leading-param-119r3i

use-debounce 回调

简单用法:https://codesandbox.io/s/x0jvqrwyq

与原生事件监听器结合:https://codesandbox.io/s/32yqlyo815

取消、最大等待时间和记忆化:https://codesandbox.io/s/4wvmp1xlw4

HTTP 请求:https://codesandbox.io/s/use-debounce-callback-http-y1h3m6

更新日志

https://github.com/xnimorz/use-debounce/blob/master/CHANGELOG.md

简单值的防抖

根据 https://twitter.com/dan_abramov/status/1060729512227467264 WebArchive 链接:https://web.archive.org/web/20210828073432/https://twitter.com/dan_abramov/status/1060729512227467264

import React, { useState } from 'react';
import { useDebounce } from 'use-debounce';

export default function Input() {
  const [text, setText] = useState('Hello');
  const [value] = useDebounce(text, 1000);

  return (
    <div>
      <input
        defaultValue={'Hello'}
        onChange={(e) => {
          setText(e.target.value);
        }}
      />
      <p>实际值:{text}</p>
      <p>防抖值:{value}</p>
    </div>
  );
}

这个钩子使用浅比较来比较前后的值。这意味着设置一个对象 {} 将触发防抖计时器。如果你需要比较对象(https://github.com/xnimorz/use-debounce/issues/27#issuecomment-496828063),你可以使用下面介绍的 useDebouncedCallback

防抖回调

除了用于值的 useDebounce,你还可以对回调进行防抖,这是更常见的防抖理解方式。 带有 Input 的示例(和 React 回调):https://codesandbox.io/s/x0jvqrwyq

import { useDebouncedCallback } from 'use-debounce';

function Input({ defaultValue }) {
  const [value, setValue] = useState(defaultValue);
  // 防抖回调
  const debounced = useDebouncedCallback(
    // 函数
    (value) => {
      setValue(value);
    },
    // 延迟时间(毫秒)
    1000
  );

  // 你应该使用 `e => debounced(e.target.value)`,因为 React 使用合成事件
  return (
    <div>
      <input
        defaultValue={defaultValue}
        onChange={(e) => debounced(e.target.value)}
      />
      <p>防抖值:{value}</p>
    </div>
  );
}

带有滚动的示例(和原生事件监听器):https://codesandbox.io/s/32yqlyo815

function ScrolledComponent() {
  // 仅用于显示没有不必要更新的计数器
  const updatedCount = useRef(0);
  updatedCount.current++;

  const [position, setPosition] = useState(window.pageYOffset);

  // 防抖回调
  const debounced = useDebouncedCallback(
    // 函数
    () => {
      setPosition(window.pageYOffset);
    },
    // 延迟时间(毫秒)
    800
  );

  useEffect(() => {
    const unsubscribe = subscribe(window, 'scroll', debounced);
    return () => {
      unsubscribe();
    };
  }, []);

  return (
    <div style={{ height: 10000 }}>
      <div style={{ position: 'fixed', top: 0, left: 0 }}>
        <p>防抖后的顶部位置:{position}</p>
        <p>组件重新渲染次数:{updatedCount.current}</p>
      </div>
    </div>
  );
}

debounced() 的返回值

对防抖函数 debounced 的后续调用会返回最后一次函数调用的结果。 注意,如果之前没有调用,这意味着你将得到 undefined。你应该在代码中适当地检查这一点。

示例:

it('对防抖函数 `debounced` 的后续调用会返回最后一次函数调用的结果。', () => {
  const callback = jest.fn(() => 42);

  let callbackCache;
  function Component() {
    const debounced = useDebouncedCallback(callback, 1000);
    callbackCache = debounced;
    return null;
  }
  Enzyme.mount(<Component />);

  const result = callbackCache();
  expect(callback.mock.calls.length).toBe(0);
  expect(result).toBeUndefined();

  act(() => {
    jest.runAllTimers();
  });
  expect(callback.mock.calls.length).toBe(1);
  const subsequentResult = callbackCache();

  expect(callback.mock.calls.length).toBe(1);
  expect(subsequentResult).toBe(42);
});

高级用法

取消、最大等待时间和记忆化

  1. useDebounceuseDebouncedCallback 都支持 maxWait 选项。这个参数描述了函数在被调用之前允许延迟的最长时间。
  2. 你可以通过调用 cancel 回调来取消防抖周期

完整示例可以在这里查看 https://codesandbox.io/s/4wvmp1xlw4

import React, { useState } from 'react';
import ReactDOM from 'react-dom';
import { useDebouncedCallback } from 'use-debounce';

function Input({ defaultValue }) {
  const [value, setValue] = useState(defaultValue);
  const debounced = useDebouncedCallback(
    (value) => {
      setValue(value);
    },
    500,
    // 函数被调用之前允许延迟的最长时间:
    { maxWait: 2000 }
  );

  // 你应该使用 `e => debounced(e.target.value)`,因为 React 使用合成事件
  return (
    <div>
      <input
        defaultValue={defaultValue}
        onChange={(e) => debounced(e.target.value)}
      />
      <p>防抖值:{value}</p>
      <button onClick={debounced.cancel}>取消防抖周期</button>
    </div>
  );
}

const rootElement = document.getElementById('root');
ReactDOM.render(<Input defaultValue="Hello world" />, rootElement);

useDebounce 调用也有相同的 API:

const [value, {cancel, isPending, flush}] = useDebounce(valueToDebounce);
...
cancel() // 取消待处理的防抖请求
isPending() // 返回是否有待处理的防抖请求
flush() // 立即执行待处理的请求

flush 方法

useDebouncedCallback 有一个 flush 方法。它允许在回调尚未触发时手动调用回调。当用户执行会导致组件卸载的操作,但你需要执行回调时,这个方法很有用。

import React, { useState } from 'react';
import { useDebouncedCallback } from 'use-debounce';

function InputWhichFetchesSomeData({ defaultValue, asyncFetchData }) {
  const debounced = useDebouncedCallback(
    (value) => {
      asyncFetchData;
    },
    500,
    { maxWait: 2000 }
  );

  // 当组件即将卸载时,如果输入有变化,我们将获取数据。
  useEffect(
    () => () => {
      debounced.flush();
    },
    [debounced]
  );

  return (
    <input
      defaultValue={defaultValue}
      onChange={(e) => debounced(e.target.value)}
    />
  );
}

isPending 方法

isPending 方法显示组件是否有待处理的回调。适用于 useDebounceuseDebouncedCallback

import React, { useCallback } from 'react';

function Component({ text }) {
  const debounced = useDebouncedCallback(
    useCallback(() => {}, []),
    500
  );

  expect(debounced.isPending()).toBeFalsy();
  debounced();
  expect(debounced.isPending()).toBeTruthy();
  debounced.flush();
  expect(debounced.isPending()).toBeFalsy();

  return <span>{text}</span>;
}

前缘/后缘调用

useDebounceuseDebouncedCallback 都支持 leadingtrailing 选项。leading 参数将在首次调用时立即执行函数。后续调用将被延迟直到超时。trailing 选项控制是否在超时后再次调用回调。

有关前缘防抖调用如何工作的更多信息,请参见:https://lodash.com/docs/#debounce

import React, { useState } from 'react';
import { useDebounce } from 'use-debounce';

export default function Input() {
  const [text, setText] = useState('Hello');
  const [value] = useDebounce(text, 1000, { leading: true });

  // 当文本第一次改变时,value 会立即更新,
  // 但所有后续更改都会被延迟。
  return (
    <div>
      <input
        defaultValue={'Hello'}
        onChange={(e) => {
          setText(e.target.value);
        }}
      />
      <p>实际值:{text}</p>
      <p>延迟值:{value}</p>
    </div>
  );
}

选项:

你可以为 useDebounceuseDebouncedCallback 提供第三个参数作为附加选项:

选项默认值描述示例
maxWait-描述函数被允许延迟的最长时间,超过该时间将被调用https://github.com/xnimorz/use-debounce#cancel-maxwait-and-memoization
leading-此参数将在首次调用时立即执行函数。后续调用将被延迟直到超时https://github.com/xnimorz/use-debounce#leading-calls
trailingtrue此参数在超时后执行函数https://github.com/xnimorz/use-debounce#leading-calls
equalityFn(prev, next) => prev === next[仅用于 useDebounce] 比较函数,用于判断是否应该开始超时

useThrottledCallback

从 5.2.0 版本开始,你也可以使用这个库来实现节流回调。 为此,请使用:

import useThrottledCallback from 'use-debounce/useThrottledCallback';

import { useThrottledCallback } from 'use-debounce';

几个例子:

  1. 避免在滚动时过度更新位置。

    const scrollHandler = useThrottledCallback(updatePosition, 100);
    window.addEventListener('scroll', scrollHandler);
    
  2. 当点击事件触发时调用 renewToken,但不超过每 5 分钟一次。

    const throttled = useThrottledCallback(renewToken, 300000, { 'trailing': false })
    <button onClick={throttled}>点击</button>
    

useThrottledCallback 的所有参数与 useDebouncedCallback 相同,除了 maxWait 选项。因为节流回调不需要这个选项。

特别感谢:

@tryggvigy — 管理了库的许多新功能,如前缘和后缘参数、节流回调等;

@omgovich — 减小了包的大小。

项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号