cache와의 인터랙션을 위해 사용된다.
cache를 전역적으로 사용하기 위해 처음 해야할 일은 App 컴포넌트에 queryClient
인스턴스를 생성하고 Provider에 넣어주는 것이다.
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
...
const queryClient = new QueryClient();
function Root() {
return (
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
);
}
이로써 useQueryClient
를 통해 queryClient
에 접근할 수 있게 된다.
이는 어떤 구조로 이루어져 있는지 간단하게 살펴보자.
즉 queryCache, mutationCache를 담고있다. 아래는 실제 QueryClient 구조체이다.
(잘려진 더 아래에는 당연하게도 수많은 메서드가 존재한다.)
각 메서드 종류와 역할은 공식문서를 참고한다.
export declare class QueryClient {
private queryCache;
private mutationCache;
private defaultOptions;
private queryDefaults;
private mutationDefaults;
private unsubscribeFocus?;
private unsubscribeOnline?;
constructor(config?: QueryClientConfig);
mount(): void;
unmount(): void;
...
}
queies가 있는 것을 볼 수 있다. 이를 구성하는 각 Query는 hash를 갖고있으며 이는 querykey를 stringify한 값이다. (queryKey에 유니크한 값을 할당해야하는 이유)
export declare class QueryCache extends Subscribable<QueryCacheListener> {
config: QueryCacheConfig;
private queries;
private queriesMap;
constructor(config?: QueryCacheConfig);
build<TQueryFnData, TError, TData, TQueryKey extends QueryKey>(client: QueryClient, options: QueryOptions<TQueryFnData, TError, TData, TQueryKey>, state?: QueryState<TData, TError>): Query<TQueryFnData, TError, TData, TQueryKey>;
add(query: Query<any, any, any, any>): void;
remove(query: Query<any, any, any, any>): void;
clear(): void;
get<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData, TQueyKey extends QueryKey = QueryKey>(queryHash: string): Query<TQueryFnData, TError, TData, TQueyKey> | undefined;
getAll(): Query[];
find<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData>(arg1: QueryKey, arg2?: QueryFilters): Query<TQueryFnData, TError, TData> | undefined;
findAll(queryKey?: QueryKey, filters?: QueryFilters): Query[];
findAll(filters?: QueryFilters): Query[];
findAll(arg1?: QueryKey | QueryFilters, arg2?: QueryFilters): Query[];
notify(event: QueryCacheNotifyEvent): void;
onFocus(): void;
onOnline(): void;
}
위에 설명에 이어 각 유니크한 Query는 아래와같이 구성되어있다.
export declare class Query<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey> {
queryKey: TQueryKey;
queryHash: string;
options: QueryOptions<TQueryFnData, TError, TData, TQueryKey>;
initialState: QueryState<TData, TError>;
revertState?: QueryState<TData, TError>;
state: QueryState<TData, TError>;
cacheTime: number;
meta: QueryMeta | undefined;
private cache;
private promise?;
private gcTimeout?;
private retryer?;
private observers;
...
}
이는 observers를 갖고있으며, 해당 Query가 위치한 cache(상위의 QueryCache) 정보도 갖고있다.
이를 생각해보면 아래와 같은 결론이 나게 된다. (useQuery를 호출할 시)
Query ↔️ Ovserver ↔️ Component