包装一个 React 钩子并保留其类型
Wrap a React hook and retain its types
我想包装 React 查询以便显示错误。如何键入 args、通用和 return 类型以镜像 useQuery
?
export function useRelocaterQuery<T>(...args: any): Foo {
// ^ ^ ^ type this to mirror useQuery()
const { enqueueSnackbar } = useSnackbar();
const query = useQuery(...args);
if (query.error) {
enqueueSnackbar("some generic message");
}
return query;
}
我看到您可以使用中间函数 (wrap) 对常规函数执行此操作,但我不知道如何将其扩展为挂钩。
const wrap = <T extends Array<any>, U>(fn: (...args: T) => U) => {
return (...args: T): U => fn(...args)
}
因为 useQuery 有 4 个泛型,所以 useQuery 的每个低级包装器也需要有相同的泛型。 useQuery 本身也有 3 个函数重载,所以你必须选择一个结构。最简单的解决方案是使用对象结构并基本上复制 react-query 为选项所做的任何事情。 return类型一般可以推断出来,或者需要使用UseQueryResult
:
export function useRelocaterQuery<
TQueryFnData = unknown,
TError = unknown,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey
>(
options: UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>
): UseQueryResult<TData, TError> {
const { enqueueSnackbar } = useSnackbar();
const query = useQuery(options);
if (query.error) {
enqueueSnackbar("some generic message");
}
return query;
}
作为 side-note,我通常不认为像这样的抽象是首选。首先,调用 enqueueSnackbar
可能违反了 react 渲染函数必须是纯函数的规则,因为它在渲染期间显然会产生 side-effect。所以你必须把它放在 useEffect
中,至少可以避免 React 18 及以后的并发特性出现问题。
除此之外,还有更好的方法来处理一般错误。例如,要显示错误提示,我可以在 QueryCache 上推荐 the global onError handlers:
const queryClient = new QueryClient({
queryCache: new QueryCache({
onError: (error) =>
toast.error(`Something went wrong: ${error.message}`),
}),
})
如果您需要关闭来自钩子的 enqueSnackbar
,您需要在应用程序的渲染函数中创建 QueryClient,因此您需要通过将其放入状态来使其稳定
function App() {
const { enqueueSnackbar } = useSnackbar();
const [queryClient] = React.useState(() => {
return new QueryClient({
queryCache: new QueryCache({
onError: (error) =>
enqueueSnackbar("some generic message");
}),
})
})
}
我想包装 React 查询以便显示错误。如何键入 args、通用和 return 类型以镜像 useQuery
?
export function useRelocaterQuery<T>(...args: any): Foo {
// ^ ^ ^ type this to mirror useQuery()
const { enqueueSnackbar } = useSnackbar();
const query = useQuery(...args);
if (query.error) {
enqueueSnackbar("some generic message");
}
return query;
}
我看到您可以使用中间函数 (wrap) 对常规函数执行此操作,但我不知道如何将其扩展为挂钩。
const wrap = <T extends Array<any>, U>(fn: (...args: T) => U) => {
return (...args: T): U => fn(...args)
}
因为 useQuery 有 4 个泛型,所以 useQuery 的每个低级包装器也需要有相同的泛型。 useQuery 本身也有 3 个函数重载,所以你必须选择一个结构。最简单的解决方案是使用对象结构并基本上复制 react-query 为选项所做的任何事情。 return类型一般可以推断出来,或者需要使用UseQueryResult
:
export function useRelocaterQuery<
TQueryFnData = unknown,
TError = unknown,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey
>(
options: UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>
): UseQueryResult<TData, TError> {
const { enqueueSnackbar } = useSnackbar();
const query = useQuery(options);
if (query.error) {
enqueueSnackbar("some generic message");
}
return query;
}
作为 side-note,我通常不认为像这样的抽象是首选。首先,调用 enqueueSnackbar
可能违反了 react 渲染函数必须是纯函数的规则,因为它在渲染期间显然会产生 side-effect。所以你必须把它放在 useEffect
中,至少可以避免 React 18 及以后的并发特性出现问题。
除此之外,还有更好的方法来处理一般错误。例如,要显示错误提示,我可以在 QueryCache 上推荐 the global onError handlers:
const queryClient = new QueryClient({
queryCache: new QueryCache({
onError: (error) =>
toast.error(`Something went wrong: ${error.message}`),
}),
})
如果您需要关闭来自钩子的 enqueSnackbar
,您需要在应用程序的渲染函数中创建 QueryClient,因此您需要通过将其放入状态来使其稳定
function App() {
const { enqueueSnackbar } = useSnackbar();
const [queryClient] = React.useState(() => {
return new QueryClient({
queryCache: new QueryCache({
onError: (error) =>
enqueueSnackbar("some generic message");
}),
})
})
}