axios 如何在为useQuery创建 Package 器钩子时正确定义类型

xxhby3vn  于 2023-10-18  发布在  iOS
关注(0)|答案(2)|浏览(156)

我正在将我现有的react项目迁移到typescript,并且在已经定义的useQuery Package 器方面遇到了一些麻烦。
作为参考,这里有一个我目前正在迁移的文件。

import { UseQueryOptions, useQuery } from "react-query";
import { DASHBOARD_APIS } from "../../../../utils/constants";
import { axiosConfig } from "../../../../utils/utils";

const getAlerts = (payload: AlertsPayload): Promise<AlertsResponse> => {
  return axiosConfig
    .post<AlertsResponse>(DASHBOARD_APIS.alertsList, payload)
    .then((response) => response.data);
};

export const useAlertsList = (
  pageName: "dashboard" | "list",
  payload: AlertsPayload,
  options: UseQueryOptions = {}
) => {
  return useQuery(
    ["alerts-list", pageName, payload],
    () => getAlerts(payload),
    options
  );
};

如您所见,我在一个单独的函数中调用了实际的axios,然后将其作为查询函数传递到 Package 在useAlertsList钩子中的useQuery钩子中。
然后在我的组件中,我使用这个钩子如下:

const { dataUpdatedAt, isLoading, isFetching, data } = useAlertsList(
  "dashboard",
  { page: 0, size: 10 },
  { refetchInterval: 60000 }
);

*问题:代码无法编译并抛出错误: 请检查'data'的类型为'unknown'. ts(18046)

我尝试在我的组件中直接使用useQuery钩子,如下所示:

const { dataUpdatedAt, isLoading, isFetching, data, error } = useQuery(
  ["alerts-list"],
  () => getAlerts({ page: 0, size: 10 }),
  { refetchInterval: 30000 }
);

!!This Pattern WORKS PROPERLY!!
**BUT**在我的用例中,它不是首选的,因为该特定端点将在应用程序的多个地方使用,并且创建一个 Package 器并使用它会更友好。此外,它不是首选的,因为代码库是巨大的,并且改变它的模式是一个非常巨大的工作。

  • 相关信息 *:
  • React版本:17.0.2
  • React Query版本:3.19.0
  • typescript 版本:4.5.2
    *AlertsPayloadAlertsResponsetypes.d.ts文件中在模块级别声明的类型。
9nvpjoqh

9nvpjoqh1#

问题是UseQueryOptions接受了4个泛型,但您没有提供它们,因此它们将推断为默认值。
允许将所有选项传递给useQuery有两个问题:
1.您正在创建一个非常广泛的抽象。允许自定义钩子的消费者在每个调用端传递useQuery的所有选项并不是特别有用。
1.很难打字。您需要指定4个泛型,这与react-query在内部所做的非常相似。
建议不允许传入所有选项。我知道这在JS中工作得很好,但它不容易翻译成TS。
开始时不带选项,看看需要什么,然后根据需要传入这些值。大多数情况下,它只是像enabledrefetchInterval这样的东西,这些东西很容易输入。
在即将到来的版本5中(目前处于测试阶段),您还可以以queryOptions对象的形式创建抽象,然后将其直接传递给组件中的useQuery,而无需编写自定义钩子:

const alertsListOptions = (
  pageName: "dashboard" | "list",
  payload: AlertsPayload
) => {
  return queryOptions({
      queryKey: ["alerts-list", pageName, payload],
      queryFn: () => getAlerts(payload)
    }
  )
}

那么,在您的组件中,使用情况将是:

useQuery(alertsListOptions('dashboard', payload))

// or:
useQuery({
  ...alertsListOptions('dashboard', payload),
  enabled: someCondition
})

// or:
useQuery({
  ...alertsListOptions('dashboard', payload),
  select: someTransformation
})

所有类型都将被推断出来,所以调用端可以选择传递他们想要的任何选项,而不必编写这些类型。但是你不能用定制的钩子轻易地做到这一点。
这是TypeScript Playground

8iwquhpp

8iwquhpp2#

有个办法

export const useAlertsList = (
  pageName: "dashboard" | "list",
  payload: AlertsPayload,
  options: UseQueryOptions = {}
) => {
  return useQuery<AlertsResponse>(
    ["alerts-list", pageName, payload],
    () => getAlerts(payload),
    options
  );
};

相关问题