svelte-query — это библиотека для управления асинхронными запросами и состоянием данных в приложениях на SvelteKit. Она позволяет удобно выполнять HTTP-запросы, кэшировать результаты, автоматически обновлять данные и управлять состояниями загрузки и ошибок.
Ключевые преимущества использования svelte-query:
loading,
error и data.Для интеграции svelte-query в проект SvelteKit нужно установить пакет:
npm install @tanstack/svelte-query
Затем в корневом компоненте приложения (например,
+layout.svelte) необходимо подключить
QueryClient и QueryClientProvider:
<script lang="ts">
import { QueryClient, QueryClientProvider } from '@tanstack/svelte-query';
const queryClient = new QueryClient();
</script>
<QueryClientProvider client={queryClient}>
<slot />
</QueryClientProvider>
Это создаёт контекст для всех дочерних компонентов, где можно будет использовать хуки для запросов данных.
useQueryuseQuery — основной хук для получения данных. Он
принимает объект с ключом запроса и функцией-фетчером:
<script lang="ts">
import { useQuery } from '@tanstack/svelte-query';
const fetchTodos = async () => {
const res = await fetch('/api/todos');
if (!res.ok) throw new Error('Ошибка загрузки');
return res.json();
};
const todosQuery = useQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
staleTime: 1000 * 60 // 1 минута
});
</script>
{#if todosQuery.isLoading}
<p>Загрузка...</p>
{:else if todosQuery.isError}
<p>Ошибка: {todosQuery.error.message}</p>
{:else}
<ul>
{#each todosQuery.data as todo}
<li>{todo.title}</li>
{/each}
</ul>
{/if}
Основные свойства объекта запроса:
isLoading — активен, пока данные загружаются.isError — true при возникновении ошибки.data — результат запроса.error — объект ошибки.refetch — функция повторного запроса данных.Параметр staleTime позволяет задавать
время, в течение которого кэш считается актуальным, что уменьшает
количество сетевых запросов.
useMutationДля изменения данных на сервере используется
useMutation. Она подходит для POST, PUT, PATCH и
DELETE-запросов. Пример добавления новой задачи:
<script lang="ts">
import { useMutation, useQueryClient } from '@tanstack/svelte-query';
const queryClient = useQueryClient();
const addTodo = async (newTodo) => {
const res = await fetch('/api/todos', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newTodo)
});
if (!res.ok) throw new Error('Ошибка добавления');
return res.json();
};
const mutation = useMutation(addTodo, {
onSuccess: () => {
queryClient.invalidateQueries(['todos']);
}
});
const handleAdd = async () => {
await mutation.mutateAsync({ title: 'Новая задача' });
};
</script>
<button on:click={handleAdd}>Добавить задачу</button>
Ключевые моменты:
mutateAsync позволяет работать с асинхронными функциями
и использовать await.onSuccess и onError — хуки обратного
вызова после завершения запроса.queryClient.invalidateQueries автоматически обновляет
кэшированные данные после мутации.svelte-query поддерживает глобальные настройки через
QueryClient, которые влияют на все запросы:
const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
retry: 1,
staleTime: 5 * 60 * 1000
},
mutations: {
retry: 0
}
}
});
Основные параметры:
refetchOnWindowFocus — повторный запрос при возврате на
вкладку браузера.retry — количество попыток повторного запроса при
ошибке.staleTime — время, в течение которого данные считаются
свежими.svelte-query хранит результаты запросов в кэше с
уникальными ключами (queryKey). При вызове
useQuery с уже существующим ключом данные берутся из кэша.
Если кэш устарел (staleTime прошёл), автоматически
выполняется повторный запрос.
Дополнительные методы работы с кэшем:
queryClient.getQueryData(['todos']) — получить текущие
данные.queryClient.setQueryData(['todos'], newData) — обновить
кэш вручную.queryClient.invalidateQueries(['todos']) — пометить кэш
как устаревший для автоматического обновления.Оптимистические обновления позволяют мгновенно изменять UI до получения подтверждения от сервера:
const mutation = useMutation(addTodo, {
onMutate: async (newTodo) => {
await queryClient.cancelQueries(['todos']);
const previousTodos = queryClient.getQueryData(['todos']);
queryClient.setQueryData(['todos'], [...previousTodos, newTodo]);
return { previousTodos };
},
onError: (err, newTodo, context) => {
queryClient.setQueryData(['todos'], context.previousTodos);
},
onSettled: () => {
queryClient.invalidateQueries(['todos']);
}
});
svelte-query легко интегрируется с +server.ts и
+page.ts для загрузки данных через API маршруты.
Например:
// src/routes/api/todos/+server.ts
import type { RequestHandler } from './$types';
export const GET: RequestHandler = async () => {
const todos = await fetchTodosFromDB();
return new Response(JSON.stringify(todos), { status: 200 });
};
В компоненте:
const todosQuery = useQuery({
queryKey: ['todos'],
queryFn: async () => {
const res = await fetch('/api/todos');
return res.json();
}
});
Такой подход обеспечивает разделение логики загрузки данных и UI, улучшая структуру приложения.
useQuery поддерживает реактивные зависимости через
queryKey. Если ключ содержит реактивное значение, запрос
будет автоматически обновляться при его изменении:
<script lang="ts">
import { writable } from 'svelte/store';
import { useQuery } from '@tanstack/svelte-query';
const userId = writable(1);
const userQuery = useQuery({
queryKey: ['user', $userId],
queryFn: async ({ queryKey }) => {
const res = await fetch(`/api/users/${queryKey[1]}`);
return res.json();
}
});
</script>
Изменение значения userId вызовет повторный запрос
данных пользователя.
svelte-query обеспечивает эффективное управление асинхронными
данными, сокращает количество повторных запросов и упрощает
синхронизацию состояния между сервером и UI. Основные концепции —
useQuery, useMutation, глобальные
настройки QueryClient, кэширование и оптимистические
обновления — формируют мощный инструмент для построения современных
SvelteKit приложений.
Использование реактивных ключей и интеграция с API-эндпоинтами делает библиотеку гибкой и безопасной для масштабирования больших проектов.