next-unified-query
Version:
React hooks and components for next-unified-query-core
386 lines (379 loc) • 15.5 kB
text/typescript
import * as next_unified_query_core from 'next-unified-query-core';
import { FetchError, QueryConfig, ZodType, FetchConfig, QueryFetcher, ExtractParams, QueryObserverResult, ExtractQueryData, ApiErrorResponse, RequestConfig, MutationMethod, NextTypeFetch, z, MutationConfig, QueryClient, QueryClientOptions, QueryState } from 'next-unified-query-core';
import * as React$1 from 'react';
import React__default, { ReactNode } from 'react';
/**
* 기본 UseQuery 옵션 (공통 속성)
*/
interface BaseUseQueryOptions<T = any> {
cacheKey: readonly unknown[];
params?: Record<string, any>;
schema?: ZodType;
fetchConfig?: Omit<FetchConfig, "url" | "method" | "params" | "data">;
enabled?: boolean;
staleTime?: number;
select?: (data: T) => any;
selectDeps?: any[];
/**
* placeholderData: fetch 전 임시 데이터 또는 이전 데이터 유지
* 값 또는 함수(prevData, prevQuery) 모두 지원
* ReactNode(JSX)도 허용
*/
placeholderData?: T | React.ReactNode | ((prevData: T | React.ReactNode | undefined, prevQuery?: any) => T | React.ReactNode);
/**
* gcTime: 쿼리 데이터가 사용되지 않을 때(구독자가 0이 될 때) 가비지 컬렉션까지의 시간(ms)
* 이는 생명주기 관리 전략으로, maxQueries(메모리 보호)와는 별개로 동작합니다.
* @default 300000 (5분)
*/
gcTime?: number;
/**
* 에러 발생 시 Error Boundary로 전파할지 여부
* - boolean: true면 모든 에러를 Error Boundary로 전파
* - function: 조건부 전파 (예: (error) => error.response?.status >= 500)
* @default false
*/
throwOnError?: boolean | ((error: FetchError) => boolean);
/**
* Suspense 모드 활성화 여부
* true로 설정하면 로딩 중일 때 Promise를 throw하여 React Suspense와 통합됩니다.
* @default false
*/
suspense?: boolean;
}
/**
* URL 기반 UseQuery 옵션
*/
interface UrlBasedUseQueryOptions<T = any> extends BaseUseQueryOptions<T> {
/**
* API 요청 URL
*/
url: string;
/**
* queryFn이 있으면 안됨 (상호 배제)
*/
queryFn?: never;
}
/**
* Custom Function 기반 UseQuery 옵션
*/
interface FunctionBasedUseQueryOptions<T = any> extends BaseUseQueryOptions<T> {
/**
* 복잡한 요청을 위한 커스텀 쿼리 함수
* Options 방식에서는 QueryFetcher만 전달 (GET/HEAD 메서드만 허용)
* 인자: fetcher (QueryFetcher 인스턴스)
*/
queryFn: (fetcher: QueryFetcher) => Promise<T>;
/**
* url이 있으면 안됨 (상호 배제)
*/
url?: never;
}
/**
* UseQuery 옵션
* URL 방식 또는 Custom Function 방식 중 하나를 선택할 수 있음
*/
type UseQueryOptions<T = any> = UrlBasedUseQueryOptions<T> | FunctionBasedUseQueryOptions<T>;
/**
* UseQuery 결과 타입
* QueryObserverResult의 alias로, 쿼리 상태와 데이터를 포함합니다.
*/
type UseQueryResult<TData = unknown, TError = FetchError> = QueryObserverResult<TData, TError>;
/**
* Schema에서 타입을 추출하는 도우미 타입
*/
type InferSchemaType<T> = T extends {
schema: infer S;
} ? S extends ZodType ? next_unified_query_core.z.infer<S> : any : any;
type UseQueryFactoryOptions<P, T> = Omit<UseQueryOptions<T>, "cacheKey" | "url" | "queryFn" | "params" | "schema" | "fetchConfig"> & (P extends void ? {
params?: P;
} : keyof P extends never ? {
params?: P;
} : {
params: P;
});
/**
* 캐싱과 상태 관리를 제공하는 데이터 페칭 React 훅입니다.
*
* **환경 호환성:**
* - ❌ 서버사이드: 서버 컴포넌트와 호환되지 않음 (React context 사용)
* - ✅ 클라이언트사이드: React context가 있는 React 컴포넌트에서 사용
* - ⚠️ SSR: "use client" 지시어가 있는 클라이언트 컴포넌트에서만 사용
*
* @example
* ```typescript
* // 클라이언트 컴포넌트에서만 사용
* "use client";
* import { useQuery } from 'next-unified-query/react';
*
* function UserProfile({ userId }: { userId: number }) {
* const { data, isLoading, error } = useQuery(api.getUser, { params: userId });
*
* if (isLoading) return <div>Loading...</div>;
* if (error) return <div>Error: {error.message}</div>;
* return <div>Hello {data.name}</div>;
* }
* ```
*/
declare function useQuery<T, E = FetchError>(query: QueryConfig<any, any>, options: UseQueryFactoryOptions<ExtractParams<typeof query>, T>): UseQueryResult<T, E>;
declare function useQuery<Q extends QueryConfig<any, any>, E = FetchError>(query: Q, options: UseQueryFactoryOptions<ExtractParams<Q>, ExtractQueryData<Q>>): UseQueryResult<ExtractQueryData<Q>, E>;
declare function useQuery<O extends UseQueryOptions<any> & {
schema: ZodType;
}, E = FetchError>(options: O): UseQueryResult<InferSchemaType<O>, E>;
declare function useQuery<T, E = FetchError>(options: UseQueryOptions<T>): UseQueryResult<T, E>;
/**
* Mutation 상태 인터페이스
*/
interface MutationState<TData = unknown, TError = FetchError<ApiErrorResponse>, TVariables = void> {
data: TData | undefined;
error: TError | null;
isPending: boolean;
isSuccess: boolean;
isError: boolean;
}
/**
* 기본 UseMutation 옵션 (공통 속성)
* 간소화된 타입 파라미터: TVariables, TData, TError
*/
interface BaseUseMutationOptions<TVariables = any, TData = unknown, TError = FetchError<ApiErrorResponse>> {
/**
* Mutation 실행 전 호출되는 콜백 (Optimistic Update 등에 사용)
* 반환값은 context로 다른 콜백에 전달됨
*/
onMutate?: (variables: TVariables) => Promise<any> | any;
/**
* Mutation 성공 시 호출되는 콜백
*/
onSuccess?: (data: TData, variables: TVariables, context: any) => Promise<void> | void;
/**
* Mutation 실패 시 호출되는 콜백
*/
onError?: (error: TError, variables: TVariables, context: any) => Promise<void> | void;
/**
* Mutation 완료 시 (성공/실패 무관) 호출되는 콜백
*/
onSettled?: (data: TData | undefined, error: TError | null, variables: TVariables, context: any) => Promise<void> | void;
/**
* Mutation 성공 시 무효화할 쿼리 키 목록
*/
invalidateQueries?: string[][] | ((data: TData, variables: TVariables, context: any) => string[][]);
/**
* 추가 fetch 설정 (baseURL, headers, timeout 등)
*/
fetchConfig?: Omit<RequestConfig, "url" | "method" | "params" | "data" | "schema">;
/**
* 요청 데이터 검증용 Zod 스키마 (선택적)
*/
requestSchema?: ZodType<TVariables>;
/**
* 응답 데이터 검증용 Zod 스키마 (선택적)
*/
responseSchema?: ZodType<TData>;
/**
* Mutation 에러 발생 시 Error Boundary로 전파할지 여부
* - boolean: true면 모든 에러를 Error Boundary로 전파
* - function: 조건부 전파 (예: (error) => error.response?.status >= 500)
* @default false
*/
throwOnError?: boolean | ((error: TError) => boolean);
}
/**
* URL 기반 UseMutation 옵션
*/
interface UrlBasedUseMutationOptions<TVariables = any, TData = unknown, TError = FetchError<ApiErrorResponse>> extends BaseUseMutationOptions<TVariables, TData, TError> {
/**
* API 요청 URL
*/
url: string | ((variables: TVariables) => string);
/**
* HTTP 메서드 (Mutation 가능한 메서드만)
*/
method: MutationMethod;
/**
* mutationFn이 있으면 안됨 (상호 배제)
*/
mutationFn?: never;
}
/**
* Function 기반 UseMutation 옵션 (통일된 시그니처)
*/
interface FunctionBasedUseMutationOptions<TVariables = any, TData = unknown, TError = FetchError<ApiErrorResponse>> extends BaseUseMutationOptions<TVariables, TData, TError> {
/**
* Custom mutation function - (variables, fetcher) 패턴 사용
*/
mutationFn: (variables: TVariables, fetcher: NextTypeFetch) => Promise<TData>;
/**
* url/method가 있으면 안됨 (상호 배제)
*/
url?: never;
method?: never;
}
/**
* UseMutation 옵션
* URL 방식 또는 Custom Function 방식 중 하나를 선택할 수 있음
* 순서 변경: TVariables, TData, TError (사용 빈도 순)
*/
type UseMutationOptions<TVariables = any, TData = unknown, TError = FetchError<ApiErrorResponse>> = UrlBasedUseMutationOptions<TVariables, TData, TError> | FunctionBasedUseMutationOptions<TVariables, TData, TError>;
/**
* UseMutation 결과 인터페이스 (단순화된 시그니처)
*/
interface UseMutationResult<TData = unknown, TError = FetchError<ApiErrorResponse>, TVariables = any> extends MutationState<TData, TError, TVariables> {
mutate: (variables: TVariables, options?: {
onSuccess?: (data: TData, variables: TVariables, context: any) => void;
onError?: (error: TError, variables: TVariables, context: any) => void;
onSettled?: (data: TData | undefined, error: TError | null, variables: TVariables, context: any) => void;
}) => void;
mutateAsync: (variables?: TVariables, options?: {
onSuccess?: (data: TData, variables: TVariables, context: any) => void;
onError?: (error: TError, variables: TVariables, context: any) => void;
onSettled?: (data: TData | undefined, error: TError | null, variables: TVariables, context: any) => void;
}) => Promise<TData>;
reset: () => void;
}
/**
* useMutation 오버로드 선언
* 새로운 순서: TVariables, TData, TError
*/
declare function useMutation<TVariables = any, TData = unknown>(options: UseMutationOptions<TVariables, TData>): UseMutationResult<TData, FetchError, TVariables>;
declare function useMutation<TVariables = any, TData = unknown, TError = FetchError<ApiErrorResponse>>(options: UseMutationOptions<TVariables, TData, TError>): UseMutationResult<TData, TError, TVariables>;
declare function useMutation<TVariables = any, ResponseSchema extends ZodType = ZodType, TError = FetchError<ApiErrorResponse>>(options: UseMutationOptions<TVariables, any, TError> & {
responseSchema: ResponseSchema;
}): UseMutationResult<z.infer<ResponseSchema>, TError, TVariables>;
declare function useMutation<TVariables = any, TData = unknown, TError = FetchError<ApiErrorResponse>>(factoryConfig: MutationConfig<TVariables, TData, TError>, overrideOptions?: Partial<BaseUseMutationOptions<TVariables, TData, TError>>): UseMutationResult<TData, TError, TVariables>;
declare function HydrationBoundary({ state, children, }: {
state?: Record<string, QueryState>;
children: ReactNode;
}): React__default.JSX.Element;
interface QueryClientProviderProps {
/**
* QueryClient 인스턴스 (선택사항)
* 제공하지 않으면 자동으로 환경에 맞는 인스턴스를 생성합니다.
*/
client?: QueryClient;
/**
* QueryClient 설정 (권장)
* client가 제공되지 않은 경우 이 설정으로 QueryClient를 생성합니다.
* SSR과 Client 모두에서 동일한 설정이 적용됩니다.
*/
config?: QueryClientOptions;
children: ReactNode;
}
declare function QueryClientProvider({ client, config, children }: QueryClientProviderProps): React__default.JSX.Element;
declare function useQueryClient(): QueryClient;
/**
* QueryClient 설정에 접근하는 Hook
* SSR 환경에서 설정을 공유하기 위해 사용됩니다.
*/
declare function useQueryConfig(): QueryClientOptions | undefined;
/**
* Error Boundary Props
*/
interface QueryErrorBoundaryProps {
/**
* Fallback UI를 렌더링하는 함수
* @param error - 발생한 에러
* @param reset - Error Boundary를 리셋하는 함수
*/
fallback?: (error: Error, reset: () => void) => React$1.ReactNode;
/**
* 에러 발생 시 호출되는 콜백
* 에러 로깅이나 모니터링 서비스 전송에 사용
*/
onError?: (error: Error, errorInfo: {
componentStack: string;
}) => void;
/**
* Error Boundary가 리셋될 때 호출되는 콜백
*/
onReset?: () => void;
/**
* 이 키들이 변경되면 Error Boundary가 자동으로 리셋됨
*/
resetKeys?: Array<string | number>;
/**
* Error Boundary로 감쌀 컴포넌트
*/
children: React$1.ReactNode;
}
/**
* Query Error Boundary 컴포넌트
*
* React 공식 Error Boundary 패턴을 기반으로 Next Unified Query에 최적화된 Error Boundary입니다.
* 하위 컴포넌트에서 발생하는 에러를 캐치하고 fallback UI를 표시합니다.
*
* @example
* ```tsx
* <QueryErrorBoundary
* fallback={(error, reset) => (
* <div>
* <p>Error: {error.message}</p>
* <button onClick={reset}>Retry</button>
* </div>
* )}
* onError={(error) => console.error(error)}
* >
* <MyComponent />
* </QueryErrorBoundary>
* ```
*/
/**
* QueryErrorBoundaryComponent 인터페이스
* React 18/19 호환을 위한 커스텀 타입 정의
*
* @important 이 인터페이스는 React 버전 간 호환성을 위해 필수적입니다.
* React.FC나 다른 내장 타입을 사용하면 React 18과 19 사이의 타입 불일치로 인해
* 컴파일 에러가 발생할 수 있습니다.
*/
interface QueryErrorBoundaryComponent {
(props: QueryErrorBoundaryProps): React$1.JSX.Element;
displayName?: string;
}
/**
* Query Error Boundary 컴포넌트 구현
*
* @important React 18/19 호환성을 위해 다음과 같이 구현됨:
* 1. 함수 시그니처에서 QueryErrorBoundaryProps 타입 명시 (타입 추론 유지)
* 2. React.createElement 사용 (클래스 컴포넌트를 함수로 래핑)
* 3. as any 캐스팅 (React 버전 간 타입 차이 해결)
* 4. 반환 타입을 React.JSX.Element로 명시 (일관된 타입)
* 5. QueryErrorBoundaryComponent 인터페이스로 캐스팅 (타입 안정성)
*/
declare const QueryErrorBoundary: QueryErrorBoundaryComponent;
/**
* Error Boundary를 리셋하는 함수를 반환하는 Hook
*
* @example
* ```tsx
* function MyComponent() {
* const resetErrorBoundary = useErrorResetBoundary();
*
* const handleRetry = () => {
* // 상태 초기화 등의 작업 수행
* resetErrorBoundary();
* };
* }
* ```
*/
declare const useErrorResetBoundary: () => () => void;
interface QueryErrorResetBoundaryProps extends Omit<QueryErrorBoundaryProps, "resetKeys" | "onReset"> {
/**
* Error Boundary가 리셋될 때 호출되는 콜백
*/
onReset?: () => void;
}
/**
* Error Reset Boundary 컴포넌트
*
* QueryErrorBoundary를 감싸고 리셋 기능을 Context로 제공합니다.
* 하위 컴포넌트에서 useErrorResetBoundary Hook을 사용하여 Error Boundary를 리셋할 수 있습니다.
*
* @example
* ```tsx
* <QueryErrorResetBoundary
* fallback={(error, reset) => <ErrorFallback error={error} reset={reset} />}
* >
* <App />
* </QueryErrorResetBoundary>
* ```
*/
declare function QueryErrorResetBoundary({ children, onReset, ...errorBoundaryProps }: QueryErrorResetBoundaryProps): React__default.JSX.Element;
export { HydrationBoundary, type MutationState, QueryClientProvider, QueryErrorBoundary, type QueryErrorBoundaryProps, QueryErrorResetBoundary, type QueryErrorResetBoundaryProps, type UseMutationOptions, type UseQueryOptions, type UseQueryResult, useErrorResetBoundary, useMutation, useQuery, useQueryClient, useQueryConfig };