沙箱链接:https://codesandbox.io/s/youthful-mclean-csm60i?file=/src/useFetch.ts
我的类型:
type TUseFetchLoadingState = {
loading: true;
data: never;
update: never;
mutate: never;
error: never;
};
type TUseFetchLoadedState<T> = {
data: T;
loading: never;
update: Dispatch<SetStateAction<T>>;
mutate: KeyedMutator<T>;
error: never;
};
type TUseFetchErrorState = {
error: AxiosError;
loading: never;
data: never;
update: never;
mutate: never;
};
type TUseFetchReturnType<T> = TUseFetchLoadingState | TUseFetchLoadedState<T> | TUseFetchErrorState;
钩:
const useFetch = <T>(url: string | null): TUseFetchReturnType<T> => {
const { data, error, mutate } = useSWR<T, AxiosError>(url ? url : null);
const [fetchedData, setFetchedData] = useState<T>();
useEffect(() => {
if (data) setFetchedData(data);
}, [data]);
if (!fetchedData && !error) {
return {
loading: true,
};
}
if (error) {
return {
error,
};
}
return {
data: fetchedData as T,
update: setFetchedData as Dispatch<SetStateAction<T>>,
mutate,
};
};
钩子的思想是,当我从服务器(服务器端状态)检索数据时,我将其存储在本地状态,以便我可以更改UI,而无需等待服务器端状态重新验证和更新UI。
我想正确地键入函数的返回类型,这样当没有数据和错误时,它的返回类型将是{ loading:true }
,以便稍后在组件中我可以进行typeguard。
...
if (!loading) { ... } // means there's either data or error
...
if (!error) { ... } // means no error, data fetched successfully
如果检索到的数据没有任何错误,则应该返回数据、数据设置器和mutator,以便立即重新验证服务器端状态。
当出现错误时,我只想返回error
对象。
我希望它如何在组件中使用:
const MyComponent = () => {
const { data, update, loading, error, mutate } = useFetch(ENDPOINTS.SOME_ENDPOINT);
if (error) return <ErrorComponent error={error} />
if (loading) return <LoadingComponent />
// data is available, do something with it
return (
<Box>
{/*do something with data*/}
</Box>
);
}
我对props做了类似的操作
type RequiredTableToolbarProps = {
title: string;
};
type SelectableTableToolbarProps = RequiredTableToolbarProps & {
numSelected: number;
onDeleteSelected: () => void | Promise<void>;
};
type NonSelectableTableToolbarProps = RequiredTableToolbarProps & {
numSelected: never;
onDeleteSelected: never;
};
export type TableToolbarProps = SelectableTableToolbarProps | NonSelectableTableToolbarProps;
效果很好:要么组件同时有numSelected
和onDeleteSelected
,要么没有。
我怎么能做同样的事情与函数返回类型?
让所有具有never
type字段的类型都是可选的
Codesandbox: https://codesandbox.io/s/youthful-mclean-csm60i?file=/src/useFetch.ts
解决方案:
import { AxiosError } from 'axios';
import { Dispatch, SetStateAction, useEffect, useMemo, useState } from 'react';
import useSWR, { KeyedMutator } from 'swr';
export { useFetch };
type TUseFetchLoading = {
loading: true;
data?: never;
update?: never;
mutate?: never;
error?: never;
};
type TUseFetchLoaded<T> = {
data: T;
loading?: never;
update: Dispatch<SetStateAction<T>>;
mutate: KeyedMutator<T>;
error?: never;
};
type TUseFetchError = {
error: AxiosError;
loading?: never;
data?: never;
update?: never;
mutate?: never;
};
type TUseFetchReturnType<T> = TUseFetchLoading | TUseFetchLoaded<T> | TUseFetchError;
const useFetch = <T>(url: string | null): TUseFetchReturnType<T> => {
const { data, error, mutate } = useSWR<T, AxiosError>(url ? url : null);
const [fetchedData, setFetchedData] = useState<T>(undefined as unknown as T);
useEffect(() => {
if (data) setFetchedData(data);
}, [data]);
if (!fetchedData && !error) {
return { loading: true };
}
if (error) {
return {
error,
};
}
return {
data: fetchedData,
update: setFetchedData,
mutate,
};
};