Hooks for managing, caching and syncing asynchronous and remote data in Vue
—
Vue plugin for installing TanStack Query with global configuration, dependency injection, and lifecycle management for both Vue 2 and Vue 3 applications.
Main Vue plugin for setting up TanStack Query in your application.
/**
* Vue plugin for installing TanStack Query
* Provides QueryClient via Vue's dependency injection system
*/
interface VueQueryPlugin {
install(app: any, options?: VueQueryPluginOptions): void;
}
interface VueQueryPluginOptions {
queryClient?: QueryClient;
queryClientConfig?: QueryClientConfig;
queryClientKey?: string;
enableDevtoolsV6Plugin?: boolean;
clientPersister?: ClientPersister;
clientPersisterOnSuccess?: (client: QueryClient) => void;
}
type ClientPersister = (client: QueryClient) => [() => void, Promise<void>];
interface QueryClientConfig {
queryCache?: QueryCache;
mutationCache?: MutationCache;
defaultOptions?: DefaultOptions;
}Usage Examples:
// Vue 3 setup
import { createApp } from 'vue';
import { VueQueryPlugin, QueryClient } from '@tanstack/vue-query';
import App from './App.vue';
const app = createApp(App);
// Basic setup with default configuration
const queryClient = new QueryClient();
app.use(VueQueryPlugin, { queryClient });
// Advanced setup with custom configuration
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 60 * 5, // 5 minutes
gcTime: 1000 * 60 * 30, // 30 minutes
retry: 3,
refetchOnWindowFocus: false,
refetchOnReconnect: 'always',
},
mutations: {
retry: 1,
throwOnError: true,
},
},
});
app.use(VueQueryPlugin, {
queryClient,
enableDevtoolsV6Plugin: true,
});
app.mount('#app');
// Vue 2 setup with Composition API
import Vue from 'vue';
import VueCompositionAPI from '@vue/composition-api';
import { VueQueryPlugin, QueryClient } from '@tanstack/vue-query';
import App from './App.vue';
Vue.use(VueCompositionAPI);
const queryClient = new QueryClient();
Vue.use(VueQueryPlugin, { queryClient });
new Vue({
render: h => h(App),
}).$mount('#app');
// Setup with configuration object instead of client instance
app.use(VueQueryPlugin, {
queryClientConfig: {
defaultOptions: {
queries: {
staleTime: 1000 * 60 * 10,
retry: 2,
},
},
},
enableDevtoolsV6Plugin: process.env.NODE_ENV === 'development',
});
// Multiple client setup with keys
const mainClient = new QueryClient();
const analyticsClient = new QueryClient();
app.use(VueQueryPlugin, {
queryClient: mainClient,
queryClientKey: 'main'
});
app.use(VueQueryPlugin, {
queryClient: analyticsClient,
queryClientKey: 'analytics'
});
// Usage in components with multiple clients
export default {
setup() {
const mainClient = useQueryClient('main');
const analyticsClient = useQueryClient('analytics');
// Use different clients for different purposes
const { data: userData } = useQuery({
queryKey: ['user'],
queryFn: fetchUser,
}, mainClient);
const { mutate: trackEvent } = useMutation({
mutationFn: trackAnalyticsEvent,
}, analyticsClient);
return { userData, trackEvent };
}
};Setup for persisting query client state across application restarts.
/**
* Client persister function type for state persistence
* @param client - QueryClient instance to persist
* @returns Tuple of [unmount function, ready promise]
*/
type ClientPersister = (client: QueryClient) => [() => void, Promise<void>];Usage Examples:
import { VueQueryPlugin, QueryClient } from '@tanstack/vue-query';
import { persistQueryClient } from '@tanstack/query-persist-client-core';
import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister';
// Create persister
const persister = createSyncStoragePersister({
storage: window.localStorage,
key: 'vue-query-cache',
});
// Setup client persistence
const queryClient = new QueryClient({
defaultOptions: {
queries: {
gcTime: 1000 * 60 * 60 * 24, // 24 hours
},
},
});
app.use(VueQueryPlugin, {
queryClient,
clientPersister: (client) => {
return persistQueryClient({
queryClient: client,
persister,
maxAge: 1000 * 60 * 60 * 24, // 24 hours
});
},
clientPersisterOnSuccess: (client) => {
console.log('Query cache restored from storage');
},
});
// Custom persister implementation
const customPersister = (client) => {
let intervalId;
// Restore from storage
const storedState = localStorage.getItem('query-cache');
if (storedState) {
const parsedState = JSON.parse(storedState);
client.setQueriesData({}, parsedState);
}
// Save to storage periodically
intervalId = setInterval(() => {
const state = client.getQueriesData({});
localStorage.setItem('query-cache', JSON.stringify(state));
}, 30000); // Save every 30 seconds
const unmount = () => {
clearInterval(intervalId);
};
const ready = Promise.resolve();
return [unmount, ready];
};
app.use(VueQueryPlugin, {
queryClient,
clientPersister: customPersister,
});Setup for Vue DevTools integration to inspect query state.
interface VueQueryPluginOptions {
enableDevtoolsV6Plugin?: boolean;
}Usage Examples:
import { VueQueryPlugin, QueryClient } from '@tanstack/vue-query';
// Enable devtools in development
app.use(VueQueryPlugin, {
queryClient: new QueryClient(),
enableDevtoolsV6Plugin: process.env.NODE_ENV === 'development',
});
// Conditional devtools setup
const isDevelopment = import.meta.env.DEV;
const enableDevtools = isDevelopment && window.__VUE_DEVTOOLS_GLOBAL_HOOK__;
app.use(VueQueryPlugin, {
queryClient: new QueryClient(),
enableDevtoolsV6Plugin: enableDevtools,
});Server-side rendering configuration for Nuxt.js and other SSR frameworks.
Usage Examples:
// Nuxt 3 plugin setup
// plugins/vue-query.client.ts
import { VueQueryPlugin, QueryClient, hydrate, dehydrate } from '@tanstack/vue-query';
export default defineNuxtPlugin((nuxtApp) => {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 60 * 5,
},
},
});
// Hydrate on client
if (process.client) {
const dehydratedState = nuxtApp.ssrContext?.nuxt?.data?.vueQueryState;
if (dehydratedState) {
hydrate(queryClient, dehydratedState);
}
}
nuxtApp.vueApp.use(VueQueryPlugin, { queryClient });
return {
provide: {
queryClient,
},
};
});
// Server-side data fetching
// server/api/ssr-data.ts
export default defineEventHandler(async (event) => {
const queryClient = new QueryClient();
// Prefetch data on server
await queryClient.prefetchQuery({
queryKey: ['posts'],
queryFn: () => $fetch('/api/posts'),
});
// Dehydrate for client
const dehydratedState = dehydrate(queryClient);
return {
dehydratedState,
};
});
// Vite SSR setup
// entry-server.js
import { createApp } from 'vue';
import { VueQueryPlugin, QueryClient, dehydrate } from '@tanstack/vue-query';
import { createSSRApp } from 'vue';
export async function render(url, manifest) {
const app = createSSRApp(App);
const queryClient = new QueryClient();
app.use(VueQueryPlugin, { queryClient });
// Prefetch critical data
await queryClient.prefetchQuery({
queryKey: ['user'],
queryFn: fetchCurrentUser,
});
const html = await renderToString(app);
const state = dehydrate(queryClient);
return { html, state };
}
// entry-client.js
import { createApp } from 'vue';
import { VueQueryPlugin, QueryClient, hydrate } from '@tanstack/vue-query';
const app = createApp(App);
const queryClient = new QueryClient();
// Hydrate with server state
if (window.__INITIAL_STATE__) {
hydrate(queryClient, window.__INITIAL_STATE__.queryState);
}
app.use(VueQueryPlugin, { queryClient });
app.mount('#app');// Plugin configuration
interface VueQueryPluginOptions {
queryClient?: QueryClient;
queryClientConfig?: QueryClientConfig;
queryClientKey?: string;
enableDevtoolsV6Plugin?: boolean;
clientPersister?: ClientPersister;
clientPersisterOnSuccess?: (client: QueryClient) => void;
}
// Configuration interfaces
interface QueryClientConfig {
queryCache?: QueryCache;
mutationCache?: MutationCache;
defaultOptions?: DefaultOptions;
}
interface DefaultOptions {
queries?: QueryObserverOptions & ShallowOption;
mutations?: MutationObserverOptions & ShallowOption;
hydrate?: HydrateOptions['defaultOptions'];
dehydrate?: DehydrateOptions;
}
// Persister types
type ClientPersister = (client: QueryClient) => [() => void, Promise<void>];
// Hydration types
interface DehydrateOptions {
shouldDehydrateQuery?: (query: Query) => boolean;
shouldDehydrateMutation?: (mutation: Mutation) => boolean;
}
interface HydrateOptions {
defaultOptions?: DefaultOptions;
mutations?: Array<MutationOptions>;
queries?: Array<QueryOptions>;
}
interface DehydratedState {
mutations: Array<DehydratedMutation>;
queries: Array<DehydratedQuery>;
}
interface DehydratedQuery {
queryHash: string;
queryKey: QueryKey;
state: QueryState;
}
interface DehydratedMutation {
mutationKey?: MutationKey;
state: MutationState;
}Install with Tessl CLI
npx tessl i tessl/npm-tanstack--vue-query