Vue Query - Data Fetching Hooks
Vue Query is a library designed to simplify data fetching, caching, and synchronization for Vue applications, bringing the powerful features of TanStack Query (formerly React Query) to the Vue ecosystem. It provides a set of hooks for declarative and efficient management of asynchronous data, reducing boilerplate and improving developer experience. The current stable version is 1.26.0, but version 2.x is under active beta development, which tightly aligns its core logic with `@tanstack/query-core`. This alignment in v2 is a key differentiator, ensuring consistency with the broader TanStack Query ecosystem. It addresses common challenges like caching, background refetching, optimistic updates, and pagination out-of-the-box, making it an advanced solution compared to manual `fetch` or `axios` implementations. The library is actively maintained with ongoing feature development and bug fixes.
Common errors
-
Failed to resolve component: QueryClientProvider
cause `QueryClientProvider` was not correctly imported or registered as a component, often due to incorrect casing or not using named import.fixEnsure `import { QueryClientProvider } from 'vue-query';` is used and that you are rendering it correctly in your template or render function, e.g., `<QueryClientProvider :client="queryClient">` or `h(QueryClientProvider, { client: queryClient }, ...)`. Remember it's a named export. -
Error: A QueryClient was not found in the Vue context. Did you forget to install the QueryClientProvider?
cause The `QueryClientProvider` component was not used to wrap the application or the component attempting to use `vue-query` hooks, or the `client` prop was not passed.fixWrap your root Vue component (or the relevant part of your app) with `<QueryClientProvider :client="queryClient">` and ensure `queryClient` is an instance of `new QueryClient()`. -
TypeError: Cannot read properties of undefined (reading 'setup')
cause This usually indicates that a `vue-query` hook (or any Composition API hook) is being called outside of a Vue component's `setup()` function context.fixVerify that `useQuery`, `useMutation`, etc., are only called directly within the `setup()` method of your components or within custom composable functions that are themselves called from `setup()`.
Warnings
- breaking Version 2.0.0-beta and later migrates to `@tanstack/query-core`, which may introduce breaking changes in configuration options, API, and internal behavior. It's recommended to consult the TanStack Query documentation for core changes when upgrading to `vue-query` v2.
- breaking Starting from v2.0.0-beta.10, `vue-query` is updated to be ESM compliant, aligning with `query-core`'s move to ESM. This might affect bundler configurations or environments that rely strictly on CommonJS.
- gotcha `vue-query` requires the Vue Composition API. For Vue 2 projects, you must explicitly install and register either `@vue/composition-api` or `@nuxtjs/composition-api` (for Nuxt 2). For Vue 3, the Composition API is built-in.
- gotcha All `vue-query` hooks (e.g., `useQuery`, `useMutation`) must be called within a component's `setup()` function or another Composition API hook. Calling them outside will result in errors related to missing context.
Install
-
npm install vue-query -
yarn add vue-query -
pnpm add vue-query
Imports
- QueryClient
const QueryClient = require('vue-query')import { QueryClient } from 'vue-query' - QueryClientProvider
import QueryClientProvider from 'vue-query'
import { QueryClientProvider } from 'vue-query' - useQuery
import { useQueries } from 'vue-query'import { useQuery } from 'vue-query' - useMutation
import { useMutation } from 'vue-query'
Quickstart
import { createApp, defineComponent } from 'vue';
import { QueryClient, QueryClientProvider, useQuery } from 'vue-query';
const queryClient = new QueryClient();
const fetchTodos = async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
};
const App = defineComponent({
name: 'App',
setup() {
const { data, isLoading, isError, error } = useQuery('todo', fetchTodos);
return {
data,
isLoading,
isError,
error,
};
},
template: `
<div>
<h1>My Todo</h1>
<p v-if="isLoading">Loading todo...</p>
<p v-else-if="isError">Error: {{ error.message }}</p>
<div v-else>
<p>ID: {{ data.id }}</p>
<p>Title: {{ data.title }}</p>
<p>Completed: {{ data.completed ? 'Yes' : 'No' }}</p>
</div>
</div>
`,
});
const app = createApp({
render() {
return [
h(QueryClientProvider, { client: queryClient }, {
default: () => h(App)
})
];
}
});
app.mount('#app');