3

我试图弄清楚是否有一种方法可以为我的 React 应用程序抽象出我使用 Typescripts 泛型创建的数据获取钩子。不幸的是,我对 Typescript 的理解不如我希望的那么好,所以我陷入了困境。

我使用的钩子基于我正在使用的数据获取库 SWR 给出的示例。他们有一个我想在他们的存储库中构建的示例,但它使用的是 Axios,而我使用的是 fetch(或者确切地说是 isomorphic-unfetch)。

明确地说,我有useUsers钩子从我的用户端点获取所有用户,如下所示:

import useSWR from 'swr';
import fetcher from '../fetcher';
import { User } from '@prisma/client';

type UserHookData = {
    appUser?: User;
    isLoading: boolean;
    isError: any;
};
type UserPayload = {
    user?: User;
};

function useUsers(): UserHookData {
    const { data, error } = useSWR<UserPayload>('/api/users/', fetcher);
    const userData = data?.user;
    return {
        appUser: userData,
        isLoading: !error && !data,
        isError: error,
    };
}

export default useUsers;

使用的 fetcher 函数直接从他们的一个打字稿示例中复制而来,我使用 Prisma 作为我的 ORM,因此我可以通过它访问类型。该User类型具有电子邮件和姓名等字段。

我有另一个几乎相同的钩子来从我的项目端点获取单个项目:

import useSWR from 'swr';
import fetcher from '../fetcher';
import { Project } from '@prisma/client';

type ProjectHookData = {
    project: Project;
    isLoading: boolean;
    isError: any;
};

type ProjectPayload = {
    project?: Project;
};

function useProject(id: number): ProjectHookData {
    const { data, error } = useSWR<ProjectPayload>(`/api/project/${id}`, fetcher);
    const project = data?.project;
    return {
        project,
        isLoading: !error && !data,
        isError: error,
    };
}

export default useProject;

我想做的是有一个钩子(我们称之为 useRequest,就像在 SWR 示例中一样),我可以获取我需要的大部分数据。使用常规 Javascript,我可能会这样写:

function useRequest(url, key){
    const { data: payload, error } = UseSWR(url, fetcher);
    const data = payload[key]
    return {
         data,
         isLoading: !error && !data,
         isError: error
   };
}

但是,当我想将它用于多种不同的数据类型时,我将如何在 Typescript 中执行此操作?我考虑过为此使用泛型,但我不确定这是否是解决此问题的正确方法。

4

1 回答 1

4

以下使用泛型的钩子似乎有效:

import useSWR from 'swr';
import fetcher from './fetcher';

interface DataPaylaod<T> {
    [key: string]: T;
}

interface DataResponse<T> {
    data: T;
    isLoading: boolean;
    isError: any;
}

function useRequest<T>(url: string, key: string): DataResponse<T> {
    const { data: payload, error } = useSWR<DataPaylaod<T>>(url, fetcher);
    const data = payload ? payload[key] : undefined;
    return {
        data,
        isLoading: !data && !error,
        isError: error,
    };
}

export default useRequest;

至少它tsc以我期望的形式传递并返回数据。如果有人有更优雅的解决方案,我也很想看看。

于 2021-03-31T11:44:03.163 回答