A query function can be any function that returns a promise. The promise should resolve data or throw an error.
createQueryController(this, {
queryKey: ['todos'],
queryFn: fetchTodos,
})
createQueryController(this, () => ({
queryKey: ['todo', this.todoId],
queryFn: () => fetchTodo(this.todoId),
}))createQueryController(this, {
queryKey: ['todos'],
queryFn: fetchTodos,
})
createQueryController(this, () => ({
queryKey: ['todo', this.todoId],
queryFn: () => fetchTodo(this.todoId),
}))TanStack Query needs failed query functions to throw or return a rejected promise. Some clients do that automatically. The browser fetch API does not, so check response.ok yourself:
async function fetchTodos(): Promise<Todo[]> {
const response = await fetch('/api/todos')
if (!response.ok) {
throw new Error('Failed to fetch todos')
}
return response.json() as Promise<Todo[]>
}async function fetchTodos(): Promise<Todo[]> {
const response = await fetch('/api/todos')
if (!response.ok) {
throw new Error('Failed to fetch todos')
}
return response.json() as Promise<Todo[]>
}The thrown error is available on the query result:
const query = this.todos()
if (query.isError) {
return html`Error: ${query.error.message}`
}const query = this.todos()
if (query.isError) {
return html`Error: ${query.error.message}`
}TanStack Query passes a context object to every query function. It includes:
createQueryController(this, {
queryKey: ['todos', { status: 'open' }],
queryFn: async ({ queryKey, signal }) => {
const [, filters] = queryKey
const response = await fetch(`/api/todos?status=${filters.status}`, {
signal,
})
if (!response.ok) throw new Error('Failed to fetch todos')
return response.json() as Promise<Todo[]>
},
})createQueryController(this, {
queryKey: ['todos', { status: 'open' }],
queryFn: async ({ queryKey, signal }) => {
const [, filters] = queryKey
const response = await fetch(`/api/todos?status=${filters.status}`, {
signal,
})
if (!response.ok) throw new Error('Failed to fetch todos')
return response.json() as Promise<Todo[]>
},
})Infinite query functions also receive pageParam:
createInfiniteQueryController(this, {
queryKey: ['projects'],
queryFn: ({ pageParam }) => fetchProjectsPage(pageParam),
initialPageParam: 1,
getNextPageParam: (lastPage) =>
lastPage.hasMore ? lastPage.page + 1 : undefined,
})createInfiniteQueryController(this, {
queryKey: ['projects'],
queryFn: ({ pageParam }) => fetchProjectsPage(pageParam),
initialPageParam: 1,
getNextPageParam: (lastPage) =>
lastPage.hasMore ? lastPage.page + 1 : undefined,
})See Infinite Queries for the controller-specific behavior.