useThrottle、useDebounce 、useRquest实现

发布于:2025-02-10 ⋅ 阅读:(78) ⋅ 点赞:(0)

useRequest

import { post } from '@/api/http';
import { IResponse } from '@/types/common';
import { isString } from '@/utils/is';
import { useCallback, useEffect, useRef, useState } from 'react';
import { debounce, throttle } from 'lodash-es';
import useDebounce from './useDebounce';
import useThrottle from './useThrottle';

type TApiFn<P = any, T = any> = (params: P) => Promise<IResponse<T>>;

type TApi = string | TApiFn;

const enum EType {
  debounce = 'debounce',
  throttle = 'throttle',
}

interface IOptions<P = any, T = any> {
  manual?: boolean;
  ready?: boolean;
  params?: P;
  type?: `${EType}`;
  delay?: number;
  pollInterval?: number;
  onSuccess?: (data: T) => void;
  onFail?: () => void;
}

interface IUseRequestResult<P = any, T = any> {
  data: T;
  loading: boolean;
  request: (params?: P) => void;
  stopPolling: () => void;
}

const useRequest = <P = any, T = any>(api: TApi, options: IOptions): IUseRequestResult<P, T> => {
  const { manual, ready, params, pollInterval, type, delay } = options;
  const pollRef = useRef<number>();
  const pollingRef = useRef<boolean>(false);
  const [loading, setLoading] = useState<boolean>(false);
  const [data, setData] = useState<T>();

  const onRequest = useCallback(
    (params?: P): Promise<T> => {
      let request: unknown = api;
      if (isString(api)) {
        request = (params?: P) => post(api as string, params);
      }
      setLoading(true);
      return (request as TApiFn<P, T>)(params)
        .then((response: IResponse<T>) => {
          const { success, data } = response;
          if (success) {
            setData(data);
            return data;
          } else {
            throw response;
          }
        })
        .finally(() => setLoading(false));
    },
    [api]
  );

  const stopPolling = () => {
    if (pollRef.current) {
      pollingRef.current = false;
      clearInterval(pollRef.current);
    }
  };

  const request = useCallback(
    (_params: P = params) => {
      if (pollingRef.current) return;
      if (pollInterval) {
        pollingRef.current = true;
        pollRef.current = setInterval(() => onRequest(_params), pollInterval);
      } else {
        onRequest(_params);
      }
    },
    [onRequest]
  );

  const debounceRequest = useDebounce(request, delay);
  const throttleRequest = useThrottle(request, delay);

  const readyRequest = useCallback(() => {
    if (type === EType.debounce) {
      return debounceRequest();
    }
    if (type === EType.throttle) {
      return throttleRequest();
    }
    return request();
  }, [request]);

  useEffect(() => {
    if (!manual && ready) {
      readyRequest();
    }
  }, [api, manual, ready]);

  return { loading, data, request, stopPolling };
};

export default useRequest;

useDebounce

import { useEffect, useRef } from 'react';
import { debounce } from 'lodash-es';

/**
 * @description: 防抖hook
 * @param {function} callback
 * @param {number} delay
 * @return {*}
 */
const useDebounce = (callback: (...args: any) => void, delay: number = 500) => {
  const debounceRef = useRef<{ cancel: () => void } & ((...args: any) => void)>();

  useEffect(() => {
    debounceRef.current = debounce(callback, delay);
    return () => {
      debounceRef.current?.cancel();
    };
  }, [callback, delay]);

  return debounceRef.current;
};

export default useDebounce;

useThrottle

import { useEffect, useRef } from 'react';
import { throttle } from 'lodash-es';

/**
 * @description: 防抖hook
 * @param {function} callback
 * @param {number} delay
 * @return {*}
 */
const useThrottle = (callback: (...args: any) => void, delay: number = 500) => {
  const debounceRef = useRef<{ cancel: () => void } & ((...args: any) => void)>();

  useEffect(() => {
    debounceRef.current = throttle(callback, delay);
    return () => {
      debounceRef.current?.cancel();
    };
  }, [callback, delay]);

  return debounceRef.current;
};

export default useThrottle;


网站公告

今日签到

点亮在社区的每一天
去签到