源码链接:https://github.com/alibaba/ho...

概述

首先,useDebounceFn和useDebounce都是一个用于增加防抖性能的hook,不同之处在于useDebounceFn给函数增加防抖,而useDebounce用来给值增加防抖。

防抖

某些时候,咱们会无法控制所编写事件的触发频率;比方搜索引擎的搜寻框对于输出内容的实时反馈,以及一些依据实时数据动静更新的组件。如果在短时间内触发大量事件,可能会引起闪动甚至卡顿。

防抖(Debounce)这个概念是解决此类问题的一种办法(其余的办法比方节流)。

防抖,管制事件只会在:触发该事件,并在固定工夫内未触发第二次时,才会执行。若短时间内该事件被间断触发屡次,则会在最初一次触发的固定工夫后再执行此事件。

useDebounceFn

该hook用来包装所须要的函数,给函数增加防抖动的性能。

简略用法

以下的代码将会在点击按钮并1000毫秒内未再次点击按钮时,将value变更为2。

import { useDebounceFn } from 'ahooks';import React, { useState } from 'react';export default () => {  const [value, setValue] = useState(0);  const { run } = useDebounceFn(    (newValue) => {      setValue(newValue);    },    {      wait: 1000,    leading    },  );  return (    <div>      <p style={{ marginTop: 16 }}> Clicked count: {value} </p>      <button type="button" onClick={run(2)}>        chuange to 2      </button>    </div>  );};

参数阐明

配置参数

  • wait:防抖等待时间,默认值为1000ms(number)
  • leading:是否在提早开始前调用函数,默认为false
  • trailing:是否在提早开始后调用函数,默认为true
  • maxWait:最大等待时间,单位为ms

后果参数

  • run:触发执行传入hook的函数,参数即为函数须要的参数
  • cancel:勾销以后防抖
  • flush:立刻调用以后防抖函数

源码剖析

isDev

if (isDev) {    if (!isFunction(fn)) {      console.error(`useDebounceFn expected parameter is a function, got ${typeof fn}`);    }  }

isDev是自定义的一个环境变量,用来判断以后是否处于开发环境。

useLatest

const fnRef = useLatest(fn);
useLatest也是ahooks的一个hook,个别是用来返回某个state的最新值,防止闭包问题(比方上一篇文章中提到过的,useCallback的闭包陷阱)。

debounce

  const debounced = useMemo(    () =>      debounce(        (...args: Parameters<T>): ReturnType<T> => {          return fnRef.current(...args);        },        wait,        options,      ),    [],  );

debounce是lodash中的办法,用来解决包装函数解决防抖问题。这里应用useMemo缓存debounce这个办法,同样是为了缩小耗费。上面封装run、cancel、flush时,也是间接应用debounce的办法。

Parameters是typescript的告诫类型,用于获取函数T的参数类型,而ReturnType则是用来获取函数T的返回类型。

fnRef是应用useLatest封装好的,传入函数的最新值。

useUnmount

 useUnmount(() => {    debounced.cancel();  });

useUnmount也是ahooks封装好的hook,用来设置在组件卸载时执行的函数;为了避免内存泄露,当组件卸载时须要勾销对debounce的调用。

附上源码

import debounce from 'lodash/debounce';import { useMemo } from 'react';import type { DebounceOptions } from '../useDebounce/debounceOptions';import useLatest from '../useLatest';import useUnmount from '../useUnmount';import { isFunction } from '../utils';import isDev from '../utils/isDev';type noop = (...args: any[]) => any;function useDebounceFn<T extends noop>(fn: T, options?: DebounceOptions) {//判断是否开发环境  if (isDev) {    if (!isFunction(fn)) {      console.error(`useDebounceFn expected parameter is a function, got ${typeof fn}`);    }  }  const fnRef = useLatest(fn);  const wait = options?.wait ?? 1000;  const debounced = useMemo(    () =>      debounce(        (...args: Parameters<T>): ReturnType<T> => {          return fnRef.current(...args);        },        wait,        options,      ),    [],  );  useUnmount(() => {    debounced.cancel();  });  return {    run: debounced,    cancel: debounced.cancel,    flush: debounced.flush,  };}export default useDebounceFn;

useDebounce

剖析过useDebounceFn后,useDebounce的源码较为简单,间接用useState创立一个debounced,而后应用useDebounceFn封装它的更新办法setDebounced即可。

useEffect

该hook在每次依赖项扭转时会执行,与usecallback不同的是,当依赖项为空时,该hook每次从新渲染都会执行。用在这里,当传入的参数扭转时就调用一次debounce的run(当然还是遵循防抖动的规定)

源码

function useDebounce<T>(value: T, options?: DebounceOptions) {  const [debounced, setDebounced] = useState(value);  const { run } = useDebounceFn(() => {    setDebounced(value);  }, options);  useEffect(() => {    run();  }, [value]);  return debounced;}