乐趣区

关于typescript:⑤reactahooks源码分析之useDebounceFn和useDebounce

源码链接: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;
}
退出移动版