デバウンスを使用する
import {
useState, useEffect } from 'react';
import useDebounceFn from '../useDebounceFn';
import {
DebounceOptions } from './debounceOptions';
/**
* @description: 用来处理防抖值的 Hook。
* @param {T} value 需要防抖的值
* @param {DebounceOptions} options {wait: 超时时间,单位为毫秒;leading: 是否在上升沿触发副作用函数; trailing: 是否在下降沿触发副作用函数;}
* @return {*}
*/
function useDebounce<T>(value: T, options?: DebounceOptions) {
const [debounced, setDebounced] = useState(value);
const {
run } = useDebounceFn(() => {
setDebounced(value);
}, options);
useEffect(() => {
run();
}, [value]);
return debounced;
}
export default useDebounce;
// DebounceOptions
export interface DebounceOptions {
wait?: number;
leading?: boolean;
trailing?: boolean;
}
デバウンスFnを使用する
debounced 関数には、遅延した関数呼び出しをキャンセルする cancel メソッドと、すぐに呼び出す flash メソッドが用意されています。
import debounce from 'lodash.debounce';
import {
useRef } from 'react';
import useCreation from '../useCreation';
import {
DebounceOptions } from '../useDebounce/debounceOptions';
import useUnmount from '../useUnmount';
type Fn = (...args: any) => any;
/**
* @description: 用来处理防抖函数的 Hook。
* @param {T} fn 需要防抖执行的函数
* @param {DebounceOptions} options {wait: 超时时间,单位为毫秒;leading: 是否在上升沿触发副作用函数;trailing :是否在下降沿触发副作用函数;}
* @return {*}{run: 触发执行 fn,函数参数将会传递给 fn;cancel: 取消当前防抖; flush: 当前防抖立即调用}
*/
function useDebounceFn<T extends Fn>(fn: T, options?: DebounceOptions) {
const fnRef = useRef<T>(fn);
fnRef.current = fn;
const wait = options?.wait ?? 1000;
/**
* @description: 通过useCreation 执行debounce
* @param {*}
* @return {*}
*/
const debounced = useCreation(
() =>
debounce<T>(
((...args: any[]) => {
return fnRef.current(...args);
}) as T,
wait,
options,
),
[],
);
// 卸载时取消延迟的函数调用
useUnmount(() => {
debounced.cancel();
});
return {
run: (debounced as unknown) as T,
cancel: debounced.cancel,
flush: debounced.flush,
};
}
export default useDebounceFn;
使用作成
import {
useRef } from 'react';
/**
* @description: useCreation 是 useMemo 或 useRef 的替代品。因为 useMemo 不能保证被 memo 的值一定不会被重计算,而 useCreation 可以保证这一点。
* @param {function} factory 用来创建所需对象的函数
* @param {any} deps 传入依赖变化的对象
* @return {*}
*/
export default function useCreation<T>(factory: () => T, deps: any[]) {
// 通过useRef设置一个标记initialized
const {
current } = useRef({
deps,
obj: undefined as undefined | T,
initialized: false,
});
// 判断第一次 或者依赖变化的对象发生改变时 触发factory
if (current.initialized === false || !depsAreSame(current.deps, deps)) {
current.deps = deps;
current.obj = factory();
current.initialized = true;
}
return current.obj as T;
}
/**
* @description: 判断依赖性deps是否发生改变
* @param {any} oldDeps
* @param {any} deps
* @return {*}
*/
function depsAreSame(oldDeps: any[], deps: any[]): boolean {
if (oldDeps === deps) return true;
for (const i in oldDeps) {
if (oldDeps[i] !== deps[i]) return false;
}
return true;
}
使用アンマウント
import {
useEffect } from 'react';
import usePersistFn from '../usePersistFn';
import {
isFunction } from '../utils';
/**
* @description: 只在组件 unmount 时执行的 hook。
* @param {any} fn
* @return {*}
*/
const useUnmount = (fn: any) => {
const fnPersist = usePersistFn(fn);
useEffect(
() => () => {
if (isFunction(fnPersist)) {
fnPersist();
}
},
[fnPersist],
);
};
export default useUnmount;
// utils isFunctin
/**
* @description: 判断是否是一个function
* @param {any} obj
* @return {boolean}
*/
export function isFunction(obj: any): obj is Function {
return typeof obj === 'function';
}
usePersistFn
/**
* @description: 持久化 function 的 Hook。
* @param {T} fn 需要持久化的函数
* @return {fn} 引用地址永远不会变化的 fn
*/
function usePersistFn<T extends noop>(fn: T) {
const fnRef = useRef<T>(fn);
fnRef.current = fn;
const persistFn = useRef<T>();
if (!persistFn.current) {
persistFn.current = function (...args) {
return fnRef.current!.apply(this, args);
} as T;
}
return persistFn.current!;
}
export default usePersistFn;