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;
相关推荐
Eloudy2 小时前
ReAct 原理简介
前端·javascript·人工智能·react.js·agent·gpu
ZJU_统一阿萨姆3 小时前
【DSH】如何将 DeepSeek Harness 嵌入生产环境?万字解构 DeepSeek Agent Harness 的运行机制与安全边界
前端·javascript·安全
用户921080262863 小时前
4. 前端地图大量点位实时更新优化:后端推增量,前端做 diff
前端
SoaringHeart3 小时前
Flutter最佳实践:Web项目中文字体首次加载乱码问题解决
前端·flutter
西安小哥3 小时前
破局与重生:大厂前端如何借力 AI 转型“超级全栈“
前端·人工智能
sunly_4 小时前
TypeScript总结:16、面向对象速查
前端·javascript·typescript
MXN_小南学前端4 小时前
React超长文本域中实现“返回顶部”浮动按钮
前端·javascript·react.js
学习嵌入式的小周4 小时前
Notepad++8.8.7下载安装(附安装包)
前端·notepad++
gs801405 小时前
解构 Cordis:面向“时空可组合性”的 TypeScript 元框架深度剖析
前端·javascript·typescript
岁岁种桃花儿5 小时前
Vue核心语法第一篇:Vue是什么?
前端·javascript·vue.js