function debounce(fun, delay) {
return function (args) {
let that = this
let _args = args
clearTimeout(fun.id)
fun.id = setTimeout(function () {
fun.call(that, _args)
}, delay)
}
}
複製代碼
首先,基於react useEffect實現一個useUpdateEffect,在防抖和節流hook的實現中都會用到:react
import { useEffect, useRef } from 'react';
const useUpdateEffect: typeof useEffect = (effect, deps) => {
const isMounted = useRef(false);
useEffect(() => {
if (!isMounted.current) {
isMounted.current = true;
} else {
return effect();
}
}, deps);
};
export default useUpdateEffect;
複製代碼
接着,基於react useCallback、useUpdateEffect實現函數防抖useDebounceFn:git
import { DependencyList, useCallback, useEffect, useRef } from 'react';
import useUpdateEffect from '../useUpdateEffect';
type noop = (...args: any[]) => any;
export interface ReturnValue<T extends any[]> {
run: (...args: T) => void;
cancel: () => void;
}
function useDebounceFn<T extends any[]>(fn: (...args: T) => any, wait: number): ReturnValue<T>;
function useDebounceFn<T extends any[]>(
fn: (...args: T) => any,
deps: DependencyList,
wait: number,
): ReturnValue<T>;
function useDebounceFn<T extends any[]>(
fn: (...args: T) => any,
deps: DependencyList | number,
wait?: number,
): ReturnValue<T> {
const _deps: DependencyList = (Array.isArray(deps) ? deps : []) as DependencyList;
const _wait: number = typeof deps === 'number' ? deps : wait || 0;
const timer = useRef<any>();
const fnRef = useRef<noop>(fn);
fnRef.current = fn;
const cancel = useCallback(() => {
if (timer.current) {
clearTimeout(timer.current);
}
}, []);
const run = useCallback(
(...args: any) => {
cancel();
timer.current = setTimeout(() => {
fnRef.current(...args);
}, _wait);
},
[_wait, cancel],
);
useUpdateEffect(() => {
run();
return cancel;
}, [..._deps, run]);
useEffect(() => cancel, []);
return {
run,
cancel,
};
}
export default useDebounceFn;
複製代碼
如何使用useDebounceFn這個防抖hook,舉個例子:github
效果:快速點擊button會頻繁調用 run,但只會在全部點擊完成 500ms 後執行一次相關函數。瀏覽器
import React, { useState } from 'react';
import { Button } from 'antd';
import { useDebounceFn } from '../useDebounceFn';
export default () => {
const [value, setValue] = useState(0);
const { run } = useDebounceFn(() => {
setValue(value + 1);
}, 500);
return (
<div>
<p
style={{
marginTop: 16,
}}
>
{' '}
Clicked count: {value}{' '}
</p>
<Button onClick={run}>Click fast!</Button>
</div>
);
};
複製代碼
function throttle(fun, delay) {
let last, deferTimer
return function (args) {
let that = this
let _args = arguments
let now = +new Date()
if (last && now < last + delay) {
clearTimeout(deferTimer)
deferTimer = setTimeout(function () {
last = now
fun.apply(that, _args)
}, delay)
}else {
last = now
fun.apply(that,_args)
}
}
}
複製代碼
import { DependencyList, useCallback, useEffect, useRef } from 'react';
import useUpdateEffect from '../useUpdateEffect';
type noop = (...args: any[]) => any;
export interface ReturnValue<T extends any[]> {
run: (...args: T) => void;
cancel: () => void;
}
function useThrottleFn<T extends any[]>(fn: (...args: T) => any, wait: number): ReturnValue<T>;
function useThrottleFn<T extends any[]>(
fn: (...args: T) => any,
deps: DependencyList,
wait: number,
): ReturnValue<T>;
function useThrottleFn<T extends any[]>(
fn: (...args: T) => any,
deps: DependencyList | number,
wait?: number,
): ReturnValue<T> {
const _deps: DependencyList = (Array.isArray(deps) ? deps : []) as DependencyList;
const _wait: number = typeof deps === 'number' ? deps : wait || 0;
const timer = useRef<any>();
const fnRef = useRef<noop>(fn);
fnRef.current = fn;
const currentArgs = useRef<any>([]);
const cancel = useCallback(() => {
if (timer.current) {
clearTimeout(timer.current);
}
timer.current = undefined;
}, []);
const run = useCallback(
(...args: any) => {
currentArgs.current = args;
if (!timer.current) {
timer.current = setTimeout(() => {
fnRef.current(...currentArgs.current);
timer.current = undefined;
}, _wait);
}
},
[_wait, cancel],
);
useUpdateEffect(() => {
run();
}, [..._deps, run]);
useEffect(() => cancel, []);
return {
run,
cancel,
};
}
export default useThrottleFn;
複製代碼
如何使用useThrottleFn這個節流hook,舉個例子:bash
效果:快速點擊button會頻繁調用 run,但只會每隔 500ms 執行一次相關函數。antd
import React, { useState } from 'react';
import { Button } from 'antd';
import { useThrottleFn } from '../useThrottleFn';
export default () => {
const [value, setValue] = useState(0);
const { run } = useThrottleFn(() => {
setValue(value + 1);
}, 500);
return (
<div>
<p
style={{
marginTop: 16,
}}
>
{' '}
Clicked count: {value}{' '}
</p>
<Button onClick={run}>Click fast!</Button>
</div>
);
};
複製代碼