CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-tanstack--vue-query

Hooks for managing, caching and syncing asynchronous and remote data in Vue

Pending
Overview
Eval results
Files

queries.mddocs/

Data Queries

Core composables for fetching and caching data with reactive state management, automatic background refetching, cache invalidation, and optimistic updates.

Capabilities

useQuery

Main composable for data fetching with intelligent caching and background synchronization.

/**
 * Main composable for data fetching with intelligent caching
 * @param options - Query configuration options with Vue reactivity support
 * @param queryClient - Optional query client instance
 * @returns Reactive query state and utilities
 */
function useQuery<TQueryFnData, TError, TData, TQueryKey>(
  options: UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
  queryClient?: QueryClient
): UseQueryReturnType<TData, TError>;

// Overload for queries with defined initial data
function useQuery<TQueryFnData, TError, TData, TQueryKey>(
  options: DefinedInitialQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
  queryClient?: QueryClient
): UseQueryDefinedReturnType<TData, TError>;

interface UseQueryOptions<TQueryFnData, TError, TData, TQueryKey> {
  queryKey: MaybeRefOrGetter<TQueryKey>;
  queryFn?: MaybeRefOrGetter<QueryFunction<TQueryFnData, TQueryKey>>;
  enabled?: MaybeRefOrGetter<boolean>;
  staleTime?: MaybeRefOrGetter<number>;
  gcTime?: MaybeRefOrGetter<number>;
  refetchInterval?: MaybeRefOrGetter<number | false>;
  refetchIntervalInBackground?: MaybeRefOrGetter<boolean>;
  refetchOnMount?: MaybeRefOrGetter<boolean | "always">;
  refetchOnWindowFocus?: MaybeRefOrGetter<boolean | "always">;
  refetchOnReconnect?: MaybeRefOrGetter<boolean | "always">;
  retry?: MaybeRefOrGetter<boolean | number | ((failureCount: number, error: TError) => boolean)>;
  retryDelay?: MaybeRefOrGetter<number | ((retryAttempt: number, error: TError) => number)>;
  select?: MaybeRefOrGetter<(data: TQueryFnData) => TData>;
  placeholderData?: MaybeRefOrGetter<TData | PlaceholderDataFunction<TData>>;
  initialData?: MaybeRefOrGetter<TData | InitialDataFunction<TData>>;
  initialDataUpdatedAt?: MaybeRefOrGetter<number | (() => number | undefined)>;
  throwOnError?: MaybeRefOrGetter<boolean | ((error: TError) => boolean)>;
  meta?: MaybeRefOrGetter<QueryMeta>;
  notifyOnChangeProps?: MaybeRefOrGetter<Array<keyof UseQueryReturnType<TData, TError>>>;
  shallow?: boolean;
}

interface UseQueryReturnType<TData, TError> {
  data: Ref<TData | undefined>;
  dataUpdatedAt: Ref<number>;
  error: Ref<TError | null>;
  errorUpdatedAt: Ref<number>;
  failureCount: Ref<number>;
  failureReason: Ref<TError | null>;
  fetchStatus: Ref<FetchStatus>;
  isError: Ref<boolean>;
  isFetched: Ref<boolean>;
  isFetchedAfterMount: Ref<boolean>;
  isFetching: Ref<boolean>;
  isInitialLoading: Ref<boolean>;
  isLoading: Ref<boolean>;
  isLoadingError: Ref<boolean>;
  isPaused: Ref<boolean>;
  isPending: Ref<boolean>;
  isPlaceholderData: Ref<boolean>;
  isRefetchError: Ref<boolean>;
  isRefetching: Ref<boolean>;
  isStale: Ref<boolean>;
  isSuccess: Ref<boolean>;
  refetch: (options?: RefetchOptions) => Promise<QueryObserverResult<TData, TError>>;
  status: Ref<QueryStatus>;
  suspense: () => Promise<UseQueryReturnType<TData, TError>>;
}

Usage Examples:

import { useQuery, keepPreviousData } from '@tanstack/vue-query';

// Basic query
const { data, isLoading, error } = useQuery({
  queryKey: ['todos'],
  queryFn: () => fetch('/api/todos').then(res => res.json())
});

// Query with reactive parameters
const userId = ref(1);
const { data: user } = useQuery({
  queryKey: () => ['user', userId.value],
  queryFn: ({ queryKey }) => fetch(`/api/users/${queryKey[1]}`).then(res => res.json()),
  enabled: () => !!userId.value
});

// Query with data transformation
const { data: processedData } = useQuery({
  queryKey: ['dashboard'],
  queryFn: () => fetch('/api/dashboard').then(res => res.json()),
  select: (data) => ({
    summary: data.metrics.reduce((acc, m) => acc + m.value, 0),
    items: data.items.filter(item => item.active)
  })
});

// Query with placeholder data
const { data } = useQuery({
  queryKey: ['posts', page],
  queryFn: ({ queryKey }) => fetch(`/api/posts?page=${queryKey[1]}`).then(res => res.json()),
  placeholderData: keepPreviousData
});

useInfiniteQuery

Composable for paginated data fetching with automatic page management and infinite scrolling support.

/**
 * Composable for paginated data fetching with infinite scrolling
 * @param options - Infinite query configuration options
 * @param queryClient - Optional query client instance
 * @returns Reactive infinite query state with page management
 */
function useInfiniteQuery<TQueryFnData, TError, TData, TQueryKey, TPageParam>(
  options: UseInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam>,
  queryClient?: QueryClient
): UseInfiniteQueryReturnType<TData, TError>;

interface UseInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam> 
  extends Omit<UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>, 'queryFn'> {
  queryFn: MaybeRefOrGetter<
    (context: QueryFunctionContext<TQueryKey, TPageParam>) => TQueryFnData | Promise<TQueryFnData>
  >;
  initialPageParam: MaybeRefOrGetter<TPageParam>;
  getNextPageParam: MaybeRefOrGetter<
    (lastPage: TQueryFnData, allPages: TQueryFnData[], lastPageParam: TPageParam, allPageParams: TPageParam[]) => TPageParam | undefined | null
  >;
  getPreviousPageParam?: MaybeRefOrGetter<
    (firstPage: TQueryFnData, allPages: TQueryFnData[], firstPageParam: TPageParam, allPageParams: TPageParam[]) => TPageParam | undefined | null
  >;
  maxPages?: MaybeRefOrGetter<number>;
}

interface UseInfiniteQueryReturnType<TData, TError> extends UseQueryReturnType<TData, TError> {
  data: Ref<InfiniteData<TData> | undefined>;
  fetchNextPage: (options?: FetchNextPageOptions) => Promise<InfiniteQueryObserverResult<TData, TError>>;
  fetchPreviousPage: (options?: FetchPreviousPageOptions) => Promise<InfiniteQueryObserverResult<TData, TError>>;
  hasNextPage: Ref<boolean>;
  hasPreviousPage: Ref<boolean>;
  isFetchingNextPage: Ref<boolean>;
  isFetchingPreviousPage: Ref<boolean>;
}

interface InfiniteData<TData, TPageParam = unknown> {
  pages: TData[];
  pageParams: TPageParam[];
}

Usage Examples:

import { useInfiniteQuery } from '@tanstack/vue-query';

// Basic infinite query
const {
  data,
  fetchNextPage,
  hasNextPage,
  isFetchingNextPage
} = useInfiniteQuery({
  queryKey: ['posts'],
  queryFn: ({ pageParam = 1 }) => 
    fetch(`/api/posts?page=${pageParam}`).then(res => res.json()),
  initialPageParam: 1,
  getNextPageParam: (lastPage, allPages) => 
    lastPage.hasNextPage ? allPages.length + 1 : undefined
});

// Infinite query with search
const searchTerm = ref('');
const {
  data: searchResults,
  fetchNextPage: loadMore,
  hasNextPage,
  isFetchingNextPage: isLoadingMore
} = useInfiniteQuery({
  queryKey: () => ['search', searchTerm.value],
  queryFn: ({ queryKey, pageParam = 0 }) =>
    fetch(`/api/search?q=${queryKey[1]}&offset=${pageParam}`)
      .then(res => res.json()),
  initialPageParam: 0,
  getNextPageParam: (lastPage, allPages, lastPageParam) =>
    lastPage.results.length === 20 ? lastPageParam + 20 : undefined,
  enabled: () => searchTerm.value.length > 0
});

// Access flattened data
const allPosts = computed(() => 
  data.value?.pages.flatMap(page => page.posts) ?? []
);

useQueries

Composable for running multiple queries in parallel with individual state management.

/**
 * Run multiple queries in parallel with individual state management
 * @param options - Configuration with array of query options and optional combine function
 * @param queryClient - Optional query client instance
 * @returns Readonly ref containing array of query results
 */
function useQueries<T extends Array<any>, TCombinedResult = UseQueriesResults<T>>(
  options: {
    queries: MaybeRefOrGetter<UseQueriesOptions<T>>;
    combine?: (results: UseQueriesResults<T>) => TCombinedResult;
    shallow?: boolean;
  },
  queryClient?: QueryClient
): Readonly<Ref<TCombinedResult>>;

type UseQueriesOptions<T extends Array<any>> = readonly [...{
  [K in keyof T]: UseQueryOptions<any, any, any, any>
}];

type UseQueriesResults<T extends Array<any>> = {
  [K in keyof T]: UseQueryReturnType<any, any>
};

Usage Examples:

import { useQueries } from '@tanstack/vue-query';

// Multiple static queries
const queries = useQueries({
  queries: [
    {
      queryKey: ['user'],
      queryFn: () => fetch('/api/user').then(res => res.json())
    },
    {
      queryKey: ['posts'],
      queryFn: () => fetch('/api/posts').then(res => res.json())
    },
    {
      queryKey: ['notifications'],
      queryFn: () => fetch('/api/notifications').then(res => res.json())
    }
  ]
});

// Access individual query results
const userQuery = computed(() => queries.value[0]);
const postsQuery = computed(() => queries.value[1]);
const notificationsQuery = computed(() => queries.value[2]);

// Dynamic queries based on reactive data
const userIds = ref([1, 2, 3]);
const userQueries = useQueries({
  queries: () => userIds.value.map(id => ({
    queryKey: ['user', id],
    queryFn: () => fetch(`/api/users/${id}`).then(res => res.json())
  }))
});

// Combined result processing
const summaryQuery = useQueries({
  queries: [
    { queryKey: ['sales'], queryFn: () => fetchSales() },
    { queryKey: ['inventory'], queryFn: () => fetchInventory() },
    { queryKey: ['orders'], queryFn: () => fetchOrders() }
  ],
  combine: (results) => ({
    isLoading: results.some(query => query.isLoading),
    hasError: results.some(query => query.isError),
    data: {
      sales: results[0].data,
      inventory: results[1].data,
      orders: results[2].data
    }
  })
});

Types

// Query option variants
interface DefinedInitialQueryOptions<TQueryFnData, TError, TData, TQueryKey>
  extends UseQueryOptions<TQueryFnData, TError, TData, TQueryKey> {
  initialData: TQueryFnData | (() => TQueryFnData);
}

interface UndefinedInitialQueryOptions<TQueryFnData, TError, TData, TQueryKey>
  extends UseQueryOptions<TQueryFnData, TError, TData, TQueryKey> {
  initialData?: undefined | (() => undefined);
}

// Return type variants
interface UseQueryDefinedReturnType<TData, TError> extends UseQueryReturnType<TData, TError> {
  data: Ref<TData>; // Never undefined when initial data is defined
}

// Infinite query specific types
interface DefinedInitialDataInfiniteOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam>
  extends UseInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam> {
  initialData:
    | InfiniteData<TQueryFnData, TPageParam>
    | (() => InfiniteData<TQueryFnData, TPageParam>);
}

interface UndefinedInitialDataInfiniteOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam>
  extends UseInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam> {
  initialData?: undefined;
}

// Page parameter function types
type GetNextPageParamFunction<TQueryFnData, TPageParam> = (
  lastPage: TQueryFnData,
  allPages: TQueryFnData[],
  lastPageParam: TPageParam,
  allPageParams: TPageParam[]
) => TPageParam | undefined | null;

type GetPreviousPageParamFunction<TQueryFnData, TPageParam> = (
  firstPage: TQueryFnData,
  allPages: TQueryFnData[],
  firstPageParam: TPageParam,
  allPageParams: TPageParam[]
) => TPageParam | undefined | null;

// Fetch options
interface FetchNextPageOptions {
  cancelRefetch?: boolean;
}

interface FetchPreviousPageOptions {
  cancelRefetch?: boolean;
}

Install with Tessl CLI

npx tessl i tessl/npm-tanstack--vue-query

docs

helpers.md

index.md

mutations.md

plugin-setup.md

queries.md

query-client.md

status-utilities.md

tile.json