Skip to content

Instantly share code, notes, and snippets.

@wobsoriano
Last active February 26, 2024 18:20
Show Gist options
  • Save wobsoriano/9a7de2d2aaf9448c2fb952d2746b6907 to your computer and use it in GitHub Desktop.
Save wobsoriano/9a7de2d2aaf9448c2fb952d2746b6907 to your computer and use it in GitHub Desktop.
TanStack Query + Vue Options API
<script lang="ts">
import { defineComponent, toRaw } from 'vue'
import {
QueryObserver,
type QueryKey,
type QueryObserverResult,
type QueryClient,
} from '@tanstack/query-core'
type Todo = {
userId: number
id: number
title: string
completed: boolean
}
export default defineComponent({
inject: ['queryClient'],
data: () => ({
todoId: 1,
result: {} as QueryObserverResult<Todo, unknown>,
observer: null as null | QueryObserver<Todo, unknown, Todo, Todo, QueryKey>,
unsubscribe: () => {}
}),
methods: {
async fetchTodo(id: number) {
const resp = await fetch('https://jsonplaceholder.typicode.com/todos/' + id)
const data = await resp.json()
return data
},
},
mounted() {
this.observer = new QueryObserver<Todo, unknown, Todo, Todo, QueryKey>(this.queryClient as QueryClient, {
queryKey: ['todo', 1],
queryFn: () => this.fetchTodo(1),
})
this.unsubscribe = this.observer.subscribe((result) => {
Object.keys(result).forEach((key) => {
// @ts-expect-error: Incompatible types
this.result[key] = result[key]
})
})
},
beforeUnmount() {
this.unsubscribe()
},
watch: {
todoId(id) {
toRaw(this.observer)?.setOptions({
queryKey: ['todo', id],
queryFn: () => this.fetchTodo(id),
})
}
}
})
</script>
<template>
<main>
<div v-if="result.isLoading">Loading...</div>
<div v-else>{{ JSON.stringify(result.data) }}</div>
<button @click="todoId++" :disabled="result.isLoading">
{{ result.isLoading ? 'Fetching...' : 'Next todo' }}
</button>
</main>
</template>
import { createApp } from 'vue'
import App from './App.vue'
import { QueryClient } from '@tanstack/query-core'
const app = createApp(App)
const queryClient = new QueryClient()
app.provide('queryClient', queryClient)
app.mount('#app')
@Tajcore
Copy link

Tajcore commented Feb 7, 2024

getting Uncaught (in promise) TypeError: Cannot read from private field from this.observer.setOptions

@wobsoriano
Copy link
Author

wobsoriano commented Feb 8, 2024

@Tajcore Looks like a Proxy bug somewhere. You can add toRaw to the observer property and the error is gone.

watch: {
  todoId(id) {
    toRaw(this.observer)?.setOptions({
      queryKey: ['todo', id],
      queryFn: () => this.fetchTodo(id),
    })
  }
}

@Tajcore
Copy link

Tajcore commented Feb 8, 2024

Oh word I'm actually writing this using a class based approach using vue-facing-decorator that doesn't support the dynamic nature of updating the queryKey sadly. would you update the gist though just asking?

Thanks seeing it now!

@Tajcore
Copy link

Tajcore commented Feb 26, 2024

Hey @wobsoriano, how would you handle mutations? with just query-core

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment