debounce 去抖

更新时间:2023-02-22 15:57:53标签:web前端

常见的防抖实现

1import { useMemo, useRef } from 'react';
2
3export function debounce<T extends (...args: any[]) => any>(fn: T, delay: number) {
4 let timer: number;
5 const cancel = () => {
6 window.clearTimeout(timer);
7 };
8 const callback = (...args: any[]) => {
9 cancel();
10 timer = window.setTimeout(() => {
11 fn(...args);
12 }, delay);
13 };
14 return [callback, cancel];
15}
16
17export const useDebounce = <T extends (...args: any[]) => any>(fn: T, delay = 500) => {
18 const ref = useRef<T>();
19 ref.current = fn;
20 return useMemo(() => {
21 return debounce((...args: any[]) => {
22 ref.current?.(...args);
23 }, delay);
24 }, [delay]) as [T, () => void];
25};

应用

results:

代码
1import { ChangeEvent, FC, useState } from 'react';
2import { useDebounce } from '@shared/utils';
3
4export const DebounceExample: FC = () => {
5
6 const [result, setResult] = useState('');
7 const [handleChange] = useDebounce((e: ChangeEvent<HTMLInputElement>) => {
8 setResult(e.target.value);
9 }, 500);
10
11 return (
12 <div>
13 <input onChange={handleChange} type="text"/>
14 <p>results: { result }</p>
15 </div>
16 );
17};

其他

1import { DependencyList, useMemo } from 'react';
2
3interface FNFactory<T>{
4 (callback: (post: () => any) => void): T;
5}
6export function trailed<T extends (...args: any[]) => any>(fn: FNFactory<T>): T {
7 let count = 0;
8 const callback = (post: () => any) => {
9 count += 1;
10 Promise.resolve().then(() => {
11 if (count > 1) return count -= 1;
12 count = 0;
13 post();
14 });
15 };
16 return fn(callback);
17}
18
19export const useTrailed = <T extends (...args: any[]) => any>(fn: FNFactory<T>, deps: DependencyList) => {
20 // eslint-disable-next-line react-hooks/exhaustive-deps
21 return useMemo(() => trailed(fn), deps);
22};

示例

代码
1import { FC, useCallback } from 'react';
2import { useTrailed } from '@shared/utils';
3import styled from 'styled-components';
4
5const Wrapper = styled.div`
6 margin: 0 0 20px 0;
7 & > *:not(:first-child) {
8 margin-left: 10px;
9 }
10`;
11export const TrailedExample: FC = () => {
12
13 const counting = useTrailed((callback) => {
14 return (num: number) => {
15 // eslint-disable-next-line no-console
16 console.log(num);
17 callback(() => {
18 // eslint-disable-next-line no-console
19 console.log('Complete!');
20 });
21 };
22 }, []);
23
24 const count = useCallback((len: number) => {
25 for (let i = 1; i <= len; i += 1) {
26 counting(i);
27 }
28 }, [counting]);
29
30 return (
31 <Wrapper>
32 <button onClick={() => count(5)}>5次打印</button>
33 <button onClick={() => count(10)}>10次打印</button>
34 </Wrapper>
35 );
36};