react - query 轮询接口

1,278 阅读1分钟

自定义hooks封装轮询接口逻辑
轮询使用react-query refetchInterval方法

export interface IDeliveryOpLogRes {
  deliveryInfoList: IDeliveryOpLogInfo[];
  hasNext: boolean;
}
export interface IDeliveryOpLogInfo {
  adviceQa: any;
  attachInfoText: string;
  attachMsg: string;
  deliveryLevelStr: string;
  deliveryNodeDesc: string;
  deliveryNodeMethod: string;
  deliveryNodeStep: string;
  deliveryNodeTypeStr: string;
  deliveryProcessName: string;
  deliveryStatus: DeliveryOpLogStatusEnum;
  attachStackTrace: string;
  id: number;
  requestIdentify: string;
  timestampStr: string;
}

/** 无数据下,最大轮询次数,避免异常状况无限轮询 */
const OP_LOG_MAX_EMPTY_POLLING_COUNT = 100;
/** 轮询间隔 */
const OP_LOG_POLLING_INTERVAL = 3000;

// 自定义hooks接受两个参数,接口参数id和请求接口的函数
function useOpLog(operationId: string, logQueryFn: (operationId: string, nextIndex?: number) => Promise<IDeliveryOpLogRes>) {
  const [emptyPollCount, setEmptyPollCount] = useState(0); // 记录无数据时的轮询次数
  
  const [nextLogIndex, setNextLogIndex] = useState<number>(null); // 轮询下一次请求的第二个参数
  const [logs, setLogs] = useState<IDeliveryOpLogInfo[]>([]); // 轮询结果得到的所有数据
  const opLogQ = useQuery(
    ['getDeliveryOpLog', operationId],
    () => logQueryFn(operationId, nextLogIndex),
    {
      enabled: !!operationId,  // 决定是否发起请求
      refetchInterval: (data) => {
        // 判断是否轮询的条件  返回轮询间隔轮询接口 返回false不轮询接口
        if (emptyPollCount >= OP_LOG_MAX_EMPTY_POLLING_COUNT) {
          return false;
        }
        if (data?.hasNext && operationId) {
          return OP_LOG_POLLING_INTERVAL;
        }
        return false;
      },
      onSuccess: (data) => {
        const { deliveryInfoList = [] } = data;
        if (deliveryInfoList.length) {
          setLogs(prev => prev.concat(deliveryInfoList));  // 新数据合并到原数据中
        }
        // 处理hasNext
        if (data.hasNext) {
          if (!deliveryInfoList.length) {
            setEmptyPollCount(prev => prev + 1); // 请求无数据时开始计数
          } else {
            setNextLogIndex(deliveryInfoList[deliveryInfoList.length - 1].id); // 获取下次请求的第二个参数
            setEmptyPollCount(0); // 接口hasNext返回false 重新开始计数 不再轮询接口
          }
        }
      },
    },
  );

  useEffect(() => {
    setEmptyPollCount(0);
    setNextLogIndex(null);
    setLogs([]);
  }, [operationId]);
  return {
    logs: [...logs].reverse(),  // 新生成的数据在上面显示
    isLoading: opLogQ.isFetching,  // 接口是否在加载
    hasNext: opLogQ.data?.hasNext,
  };
}