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
UseQueryOptionshas 4 generics on type-level. Without those, you can e.g. never use theselectoptionit 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 …