Custom Hook #8721
-
Hi, i wrote a custom hook for my workplace project and i want to ask is this pattern ok to use? the point for this hook: import useAuthStore from 'src/store/auth/useAuthStore';
import { api } from './api';
import {
queryOptions,
useQuery,
UseQueryOptions,
} from '@tanstack/react-query';
type Method = 'get' | 'post' | 'put' | 'patch' | 'delete';
interface Options extends UseQueryOptions {}
interface BackendResponse<T = unknown> {
Result: T;
Error: unknown;
Success: boolean;
}
export const useFetchData = <T,>(givenOptions: Options, method?: Method) => {
const accessToken = useAuthStore((state) => state.tokens)?.accessToken;
const { queryKey } = givenOptions;
const options = queryOptions({
queryKey,
queryFn: async () => {
return (await api(accessToken || '')[method || 'get'](queryKey.join('/')))
.data as BackendResponse<T>;
},
});
return useQuery(options);
}; |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
I see a couple of issues with this hook:
My general advice is to not build such low level abstractions, unless you’re absolutely sure you understand the trade-offs. If you build them, build them in a way that they only return And please use our eslint-plugin to avoid stale closure issues. |
Beta Was this translation helpful? Give feedback.
I see a couple of issues with this hook:
you pass in
givenOptions
, but they don’t become part of the result. That means I an pass in an additional option likestaleTime
, and it will be ignoredlow-level abstractions like this are usually much more complex because
UseQueryOptions
has 4 generics on type-level. Without those, you can e.g. never use theselect
optionit also means you can never get type inference, as you always have to provide the type for the result on every call-side:
useFetchData<Array<Todo>>({ queryKey: ['api', 'todos'] })
the method isn’t part of the key, so changing methods from the call-side will result in different requests that will share the same cache, and …