React下拉框接口请求hook封装

前言

记录一下公司 下拉框封装的 接口hook。主要是支持

  • 初始化或者指定状态下请求接口
  • 防抖搜索
  • 支持不同类型的接口(get、post)

代码

主体 hook

tsx 复制代码
import { IObj, IOption, TRecord } from "@/utils/interface";
import { to } from "@/utils/tools";
import { useMount } from "@quarkunlimit/react-hooks";
import { debounce } from "lodash";
import { useEffect, useRef, useState } from "react";
import {
  IUseMountFetchDataNewProps,
  IUseMountFetchDataResult,
} from "./interface";

/**
 * 初始化请求下拉框接口
 * @param props
 * @returns
 */
export const useSearchSelectFetchNew = (
  props: IUseMountFetchDataNewProps
): IUseMountFetchDataResult => {
  const {
    fetchDataApi,
    request,
    searchParamKey,
    transformOptions,
    refreshFetch,
    initFetch = true,
    needSetExtarData = false,
  } = props;

  const [data, setData] = useState<IOption[]>([]);
  const isMount = useRef<boolean>(false);
  const originData = useRef<IOption[]>([]);

  const fetchData = async (otherRequest?: TRecord) => {
    let newRequst: IObj = {}
    newRequst = {
        page: 1,
        size: 100,
        ...request,
        ...otherRequest
    }
    const [err, res] = await to(
      (() => {
        return fetchDataApi(newRequst);
      })()
    );
    if (!(err || !res)) {
      const data = transformOptions(res);
      setData(data);
      if (!isMount.current) {
        originData.current = data;
        isMount.current = true;
      }
    }
  };

  const onSearch = debounce((value: string) => {
    if (value.trim()) {
      fetchData({
        [searchParamKey]: value,
      });
    } else {
      setData(originData.current);
    }
  }, 500);

  useEffect(() => {
    if (refreshFetch) {
      fetchData();
    }
  }, [refreshFetch]);

  useMount(() => {
    if (initFetch) {
      fetchData();
    }
  });

  const setExtarData = (list: IOption[]) => {
    const newData: IOption[] = [];
    const idSet = new Set<string>();
    for (let item of data) {
      newData.push(item);
      idSet.add(item.value);
    }

    for (let item of list) {
      if (typeof item !== "object") {
        continue;
      }
      if (idSet.has(item?.value)) {
        continue;
      }
      idSet.add(item.value);
      newData.push(item);
    }
    setData(newData);
  };

  return {
    options: data,
    onSearch,
    onFocus: () => fetchData(),
    ...(needSetExtarData ? { setExtarData } : {}),
  };
};

类型定义

ts 复制代码
import { SelectProps } from "antd";

export interface IOption {
  label: string;
  value: string;
  [key: string]: any;
}

export interface IUseMountFetchDataNewProps {
  /**@param 接口Api */
  fetchDataApi: (...arg: any) => Promise<IApiData>;
  /**@param 初始化时接口额外参数 */
  request?: TRecord & { enableFlag?: boolean; dataScopeEnableFlag?: boolean };
  /**@param 搜索时的key */
  searchParamKey: string;
  /**@function 转换数据源为options */
  transformOptions: (res: IApiData) => IOption[];
  /**@param 满足某种条件时加载数据,使用时请将 initFetch 设置为 false  */
  refreshFetch?: boolean;
  /**@param 是否挂载时默认加载数据 */
  initFetch?: boolean;
  /** @param 是否需要setExtarData */
  needSetExtarData?: boolean;
}

export interface IUseMountFetchDataResult extends SelectProps {
  /** @param 下拉框选项 */
  options: IOption[];
  /** @function 下拉框搜索 */
  onSearch: (value: string) => void;
  /** @function 手动添加额外的数据源 */
  setExtarData?: (list: IOption[]) => void;
}

使用

tsx 复制代码
/** @function 获取字典值集合 */
export const sys_dict_value = (params?: IReqSysDictValueDictValue) => {
  return Service.get("/api/business/v1/sys-dict-value/dict-value", {
    params,
  }) as Promise<IResDetail<IResSysDictValueDictValue[]>>;
};

export interface IReqSysDictValueDictValue {
  /** @param 字典编码 */
  dictCode?: string;
  /** @param 字典编码集合 */
  dictCodeList?: string;
  /** @param 字典名称 */
  dictName?: string;
  /** @param 字典值 */
  dictValue?: string;
  /** @param 备注 */
  memo?: string;
}

export interface IResSysDictValueDictValue {
  dictCode: string;
  dictName: string;
  dictValue: string;
  enableFlag: boolean;
  id: string;
  memo: string;
  color: string;
  sortNum: number;
}

const TXDiplomaRadio = function TXDiplomaRadio_({
  initFetch = true,
  refreshFetch = false,
  extraReq = {},
  ...rest
}: ITXDiplomaRadioProps) {
  const { options } = useSearchSelectFetchNew({
    fetchDataApi: sys_dict_value(你的接口,返回promise),
    request: {
      dictCode: "diploma",
      ...extraReq,
    },
    initFetch,
    refreshFetch,
    searchParamKey: "dictName",
    transformOptions: (res) => {
      return res?.data?.map((x: IResSysDictValueDictValue) => ({
        label: x.dictName,
        value: x.dictValue,
      }));
    },
  });

  return <Radio.Group options={options} {...rest} />;
};

export default TXDiplomaRadio;
相关推荐
子兮曰5 小时前
OpenClaw入门:从零开始搭建你的私有化AI助手
前端·架构·github
吴仰晖5 小时前
使用github copliot chat的源码学习之Chromium Compositor
前端
1024小神5 小时前
github发布pages的几种状态记录
前端
不像程序员的程序媛7 小时前
Nginx日志切分
服务器·前端·nginx
北原_春希7 小时前
如何在Vue3项目中引入并使用Echarts图表
前端·javascript·echarts
尽意啊7 小时前
echarts树图动态添加子节点
前端·javascript·echarts
吃面必吃蒜7 小时前
echarts 极坐标柱状图 如何定义柱子颜色
前端·javascript·echarts
O_oStayPositive7 小时前
Vue3使用ECharts
前端·javascript·echarts
竹秋…7 小时前
echarts自定义tooltip中的内容
前端·javascript·echarts
宝贝露.7 小时前
Axure引入Echarts图无法正常显示问题
前端·javascript·echarts