snapshot of https://github.com/TanStack/query.git (main, 2026-09-16; blobs > 131072B omitted)
This commit is contained in:
9
examples/svelte/playground/.gitignore
vendored
Normal file
9
examples/svelte/playground/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/build
|
||||
/.svelte-kit
|
||||
/package
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
!lib/
|
||||
8
examples/svelte/playground/README.md
Normal file
8
examples/svelte/playground/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# Example
|
||||
|
||||
This example is a rewrite of the React Query playground example.
|
||||
|
||||
To run this example:
|
||||
|
||||
- `npm install`
|
||||
- `npm run dev`
|
||||
23
examples/svelte/playground/package.json
Normal file
23
examples/svelte/playground/package.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "@tanstack/query-example-svelte-playground",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tanstack/svelte-query": "^6.1.48",
|
||||
"@tanstack/svelte-query-devtools": "^6.1.48"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "^6.1.0",
|
||||
"@sveltejs/kit": "^2.57.1",
|
||||
"@sveltejs/vite-plugin-svelte": "^5.1.1",
|
||||
"svelte": "^5.39.3",
|
||||
"svelte-check": "^4.3.1",
|
||||
"typescript": "5.8.3",
|
||||
"vite": "^6.4.1"
|
||||
}
|
||||
}
|
||||
11
examples/svelte/playground/src/app.css
Normal file
11
examples/svelte/playground/src/app.css
Normal file
@@ -0,0 +1,11 @@
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 1rem;
|
||||
font-family:
|
||||
-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',
|
||||
'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
color: white;
|
||||
background: #0b1521;
|
||||
}
|
||||
12
examples/svelte/playground/src/app.d.ts
vendored
Normal file
12
examples/svelte/playground/src/app.d.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
// See https://kit.svelte.dev/docs/types#app
|
||||
// for information about these interfaces
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
// interface Locals {}
|
||||
// interface PageData {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
||||
export {}
|
||||
12
examples/svelte/playground/src/app.html
Normal file
12
examples/svelte/playground/src/app.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div style="display: contents">%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
37
examples/svelte/playground/src/lib/stores.svelte.ts
Normal file
37
examples/svelte/playground/src/lib/stores.svelte.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
export function ref<T>(initial: T) {
|
||||
let value = $state(initial)
|
||||
|
||||
return {
|
||||
get value() {
|
||||
return value
|
||||
},
|
||||
set value(newValue) {
|
||||
value = newValue
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export const staleTime = ref(1000)
|
||||
export const gcTime = ref(3000)
|
||||
export const errorRate = ref(0.05)
|
||||
export const queryTimeMin = ref(1000)
|
||||
export const queryTimeMax = ref(2000)
|
||||
|
||||
export const editingIndex = ref<number | null>(null)
|
||||
export const views = ref(['', 'fruit', 'grape'])
|
||||
|
||||
let initialId = 0
|
||||
const initialList = [
|
||||
'apple',
|
||||
'banana',
|
||||
'pineapple',
|
||||
'grapefruit',
|
||||
'dragonfruit',
|
||||
'grapes',
|
||||
].map((d) => ({ id: initialId++, name: d, notes: 'These are some notes' }))
|
||||
|
||||
export const list = ref(initialList)
|
||||
export const id = ref(initialId)
|
||||
|
||||
export type Todos = typeof initialList
|
||||
export type Todo = Todos[0]
|
||||
27
examples/svelte/playground/src/routes/+layout.svelte
Normal file
27
examples/svelte/playground/src/routes/+layout.svelte
Normal file
@@ -0,0 +1,27 @@
|
||||
<script lang="ts">
|
||||
import '../app.css'
|
||||
import { browser } from '$app/environment'
|
||||
import { QueryClientProvider, QueryClient } from '@tanstack/svelte-query'
|
||||
import { SvelteQueryDevtools } from '@tanstack/svelte-query-devtools'
|
||||
|
||||
const { children } = $props()
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
enabled: browser,
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Svelte Query Playground Example</title>
|
||||
</svelte:head>
|
||||
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<div id="app">
|
||||
{@render children()}
|
||||
</div>
|
||||
<SvelteQueryDevtools />
|
||||
</QueryClientProvider>
|
||||
81
examples/svelte/playground/src/routes/+page.svelte
Normal file
81
examples/svelte/playground/src/routes/+page.svelte
Normal file
@@ -0,0 +1,81 @@
|
||||
<script lang="ts">
|
||||
import { useQueryClient } from '@tanstack/svelte-query'
|
||||
import {
|
||||
staleTime,
|
||||
gcTime,
|
||||
errorRate,
|
||||
queryTimeMin,
|
||||
queryTimeMax,
|
||||
} from '../lib/stores.svelte'
|
||||
import App from './App.svelte'
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
queryClient.setDefaultOptions({
|
||||
queries: {
|
||||
staleTime: staleTime.value,
|
||||
gcTime: gcTime.value,
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<p>
|
||||
The "staleTime" and "gcTime" durations have been altered in this example to
|
||||
show how query stale-ness and query caching work on a granular level
|
||||
</p>
|
||||
<div>
|
||||
Stale Time:{' '}
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
step="1000"
|
||||
bind:value={staleTime.value}
|
||||
style="width: 100px"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
GcTime:{' '}
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
step="1000"
|
||||
bind:value={gcTime.value}
|
||||
style="width: 100px"
|
||||
/>
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
Error Rate:{' '}
|
||||
<input
|
||||
type="number"
|
||||
min="0"
|
||||
max="1"
|
||||
step=".05"
|
||||
bind:value={errorRate.value}
|
||||
style="width: 100px"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
Fetch Time Min:{' '}
|
||||
<input
|
||||
type="number"
|
||||
min="1"
|
||||
step="500"
|
||||
bind:value={queryTimeMin.value}
|
||||
style="width: 100px"
|
||||
/>{' '}
|
||||
</div>
|
||||
<div>
|
||||
Fetch Time Max:{' '}
|
||||
<input
|
||||
type="number"
|
||||
min="1"
|
||||
step="500"
|
||||
bind:value={queryTimeMax.value}
|
||||
style="width: 100px"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
<App />
|
||||
<br />
|
||||
67
examples/svelte/playground/src/routes/AddTodo.svelte
Normal file
67
examples/svelte/playground/src/routes/AddTodo.svelte
Normal file
@@ -0,0 +1,67 @@
|
||||
<script lang="ts">
|
||||
import { createMutation, useQueryClient } from '@tanstack/svelte-query'
|
||||
import {
|
||||
errorRate,
|
||||
queryTimeMin,
|
||||
queryTimeMax,
|
||||
list,
|
||||
id,
|
||||
} from '$lib/stores.svelte'
|
||||
import type { Todo } from '$lib/stores.svelte'
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
let name = $state('')
|
||||
|
||||
const postTodo = async ({ name, notes }: Omit<Todo, 'id'>) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(
|
||||
() => {
|
||||
if (Math.random() < errorRate.value) {
|
||||
return reject(
|
||||
new Error(
|
||||
JSON.stringify(
|
||||
{ postTodo: { name: $state.snapshot(name), notes } },
|
||||
null,
|
||||
2,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
const todo = { name, notes, id: id.value }
|
||||
id.value = id.value + 1
|
||||
list.value.push(todo)
|
||||
resolve(todo)
|
||||
},
|
||||
queryTimeMin.value +
|
||||
Math.random() * (queryTimeMax.value - queryTimeMin.value),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
const addMutation = createMutation(() => ({
|
||||
mutationFn: postTodo,
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['todos'] })
|
||||
},
|
||||
}))
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<input bind:value={name} disabled={addMutation.status === 'pending'} />
|
||||
|
||||
<button
|
||||
onclick={() => addMutation.mutate({ name, notes: name })}
|
||||
disabled={addMutation.status === 'pending' || !name}
|
||||
>
|
||||
Add Todo
|
||||
</button>
|
||||
|
||||
<div>
|
||||
{addMutation.status === 'pending'
|
||||
? 'Saving...'
|
||||
: addMutation.status === 'error'
|
||||
? addMutation.error.message
|
||||
: 'Saved!'}
|
||||
</div>
|
||||
</div>
|
||||
42
examples/svelte/playground/src/routes/App.svelte
Normal file
42
examples/svelte/playground/src/routes/App.svelte
Normal file
@@ -0,0 +1,42 @@
|
||||
<script lang="ts">
|
||||
import { useQueryClient } from '@tanstack/svelte-query'
|
||||
import TodosList from './TodosList.svelte'
|
||||
import EditTodo from './EditTodo.svelte'
|
||||
import AddTodo from './AddTodo.svelte'
|
||||
import { views, editingIndex } from '../lib/stores.svelte'
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<button onclick={() => queryClient.invalidateQueries()}>
|
||||
Force Refetch All
|
||||
</button>
|
||||
</div>
|
||||
<br />
|
||||
<hr />
|
||||
|
||||
{#each views.value as view}
|
||||
<div>
|
||||
<TodosList initialFilter={view} />
|
||||
<br />
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
<button
|
||||
onclick={() => {
|
||||
views.value.push('')
|
||||
}}
|
||||
>
|
||||
Add Filter List
|
||||
</button>
|
||||
<hr />
|
||||
|
||||
{#if editingIndex.value !== null}
|
||||
<EditTodo />
|
||||
<hr />
|
||||
{/if}
|
||||
|
||||
<AddTodo />
|
||||
</div>
|
||||
138
examples/svelte/playground/src/routes/EditTodo.svelte
Normal file
138
examples/svelte/playground/src/routes/EditTodo.svelte
Normal file
@@ -0,0 +1,138 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
useQueryClient,
|
||||
createQuery,
|
||||
createMutation,
|
||||
} from '@tanstack/svelte-query'
|
||||
import {
|
||||
errorRate,
|
||||
queryTimeMin,
|
||||
queryTimeMax,
|
||||
list,
|
||||
editingIndex,
|
||||
} from '$lib/stores.svelte'
|
||||
import type { Todo } from '$lib/stores.svelte'
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const fetchTodoById = async ({ id }: { id: number }): Promise<Todo> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(
|
||||
() => {
|
||||
if (Math.random() < errorRate.value) {
|
||||
return reject(
|
||||
new Error(JSON.stringify({ fetchTodoById: { id } }, null, 2)),
|
||||
)
|
||||
}
|
||||
const todo = $state.snapshot(list.value.find((d) => d.id === id))
|
||||
if (!todo) {
|
||||
return reject(
|
||||
new Error(JSON.stringify({ fetchTodoById: { id } }, null, 2)),
|
||||
)
|
||||
}
|
||||
resolve(todo)
|
||||
},
|
||||
queryTimeMin.value +
|
||||
Math.random() * (queryTimeMax.value - queryTimeMin.value),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
function patchTodo(todo?: Todo): Promise<Todo> {
|
||||
console.info('patchTodo', todo)
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(
|
||||
() => {
|
||||
if (Math.random() < errorRate.value) {
|
||||
return reject(
|
||||
new Error(JSON.stringify({ patchTodo: todo }, null, 2)),
|
||||
)
|
||||
}
|
||||
if (!todo) {
|
||||
return reject(
|
||||
new Error(JSON.stringify({ patchTodo: todo }, null, 2)),
|
||||
)
|
||||
}
|
||||
list.value = list.value.map((d) => {
|
||||
if (d.id === todo.id) {
|
||||
return $state.snapshot(todo)
|
||||
}
|
||||
return d
|
||||
})
|
||||
resolve(todo)
|
||||
},
|
||||
queryTimeMin.value +
|
||||
Math.random() * (queryTimeMax.value - queryTimeMin.value),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
const query = createQuery(() => ({
|
||||
queryKey: ['todo', { id: editingIndex.value }],
|
||||
queryFn: () => fetchTodoById({ id: editingIndex.value || 0 }),
|
||||
enabled: editingIndex.value !== null,
|
||||
}))
|
||||
|
||||
const saveMutation = createMutation(() => ({
|
||||
mutationFn: patchTodo,
|
||||
onSuccess: (data) => {
|
||||
// Update `todos` and the individual todo queries when this mutation succeeds
|
||||
queryClient.invalidateQueries({ queryKey: ['todos'] })
|
||||
queryClient.setQueryData(['todo', { id: editingIndex }], data)
|
||||
},
|
||||
}))
|
||||
|
||||
const todo = $derived(query.data)
|
||||
|
||||
const onSave = () => {
|
||||
saveMutation.mutate(todo)
|
||||
}
|
||||
|
||||
const disableEditSave = $derived(
|
||||
query.status === 'pending' || saveMutation.status === 'pending',
|
||||
)
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
{#if query.data}
|
||||
<button onclick={() => (editingIndex.value = null)}>Back</button> Editing
|
||||
Todo "{query.data.name}" (#{editingIndex.value})
|
||||
{/if}
|
||||
</div>
|
||||
{#if query.status === 'pending'}
|
||||
<span>Loading... (Attempt: {query.failureCount + 1})</span>
|
||||
{:else if query.error}
|
||||
<span>
|
||||
Error! <button onclick={() => query.refetch()}>Retry</button>
|
||||
</span>
|
||||
{:else if todo}
|
||||
<label>
|
||||
Name:{' '}
|
||||
<input bind:value={todo.name} disabled={disableEditSave} />
|
||||
</label>
|
||||
<label>
|
||||
Notes:{' '}
|
||||
<input bind:value={todo.notes} disabled={disableEditSave} />
|
||||
</label>
|
||||
<div>
|
||||
<button onclick={onSave} disabled={disableEditSave}> Save </button>
|
||||
</div>
|
||||
<div>
|
||||
{saveMutation.status === 'pending'
|
||||
? 'Saving...'
|
||||
: saveMutation.status === 'error'
|
||||
? saveMutation.error.message
|
||||
: 'Saved!'}
|
||||
</div>
|
||||
<div>
|
||||
{#if query.isFetching}
|
||||
<span>
|
||||
Background Refreshing... (Attempt: {query.failureCount + 1})
|
||||
</span>
|
||||
{:else}
|
||||
<span> </span>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
74
examples/svelte/playground/src/routes/TodosList.svelte
Normal file
74
examples/svelte/playground/src/routes/TodosList.svelte
Normal file
@@ -0,0 +1,74 @@
|
||||
<script lang="ts">
|
||||
import { createQuery } from '@tanstack/svelte-query'
|
||||
import {
|
||||
errorRate,
|
||||
queryTimeMin,
|
||||
queryTimeMax,
|
||||
list,
|
||||
editingIndex,
|
||||
} from '$lib/stores.svelte'
|
||||
import type { Todos } from '$lib/stores.svelte'
|
||||
|
||||
let { initialFilter }: { initialFilter: string } = $props()
|
||||
|
||||
let filter = $state(initialFilter)
|
||||
|
||||
const fetchTodos = async ({ filter }: { filter: string }): Promise<Todos> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(
|
||||
() => {
|
||||
if (Math.random() < errorRate.value) {
|
||||
return reject(
|
||||
new Error(JSON.stringify({ fetchTodos: { filter } }, null, 2)),
|
||||
)
|
||||
}
|
||||
resolve(list.value.filter((d) => d.name.includes(filter)))
|
||||
},
|
||||
queryTimeMin.value +
|
||||
Math.random() * (queryTimeMax.value - queryTimeMin.value),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
const query = createQuery(() => ({
|
||||
queryKey: ['todos', { filter: filter }],
|
||||
queryFn: () => fetchTodos({ filter: filter }),
|
||||
}))
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<label>
|
||||
Filter:{' '}
|
||||
<input bind:value={filter} />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{#if query.status === 'pending'}
|
||||
<span>Loading... (Attempt: {query.failureCount + 1})</span>
|
||||
{:else if query.status === 'error'}
|
||||
<span>
|
||||
Error: {query.error.message}
|
||||
<br />
|
||||
<button onclick={() => query.refetch()}>Retry</button>
|
||||
</span>
|
||||
{:else}
|
||||
<ul>
|
||||
{#if query.data}
|
||||
{#each query.data as todo}
|
||||
<li>
|
||||
{todo.name}{' '}
|
||||
<button onclick={() => (editingIndex.value = todo.id)}> Edit </button>
|
||||
</li>
|
||||
{/each}
|
||||
{/if}
|
||||
</ul>
|
||||
<div>
|
||||
{#if query.isFetching}
|
||||
<span>
|
||||
Background Refreshing... (Attempt: {query.failureCount + 1})
|
||||
</span>
|
||||
{:else}
|
||||
<span> </span>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
BIN
examples/svelte/playground/static/favicon.png
Normal file
BIN
examples/svelte/playground/static/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
15
examples/svelte/playground/svelte.config.js
Normal file
15
examples/svelte/playground/svelte.config.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import adapter from '@sveltejs/adapter-auto'
|
||||
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
const config = {
|
||||
preprocess: vitePreprocess(),
|
||||
kit: {
|
||||
adapter: adapter(),
|
||||
},
|
||||
compilerOptions: {
|
||||
runes: true,
|
||||
},
|
||||
}
|
||||
|
||||
export default config
|
||||
13
examples/svelte/playground/tsconfig.json
Normal file
13
examples/svelte/playground/tsconfig.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"extends": "./.svelte-kit/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": true
|
||||
}
|
||||
}
|
||||
6
examples/svelte/playground/vite.config.ts
Normal file
6
examples/svelte/playground/vite.config.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { sveltekit } from '@sveltejs/kit/vite'
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [sveltekit()],
|
||||
})
|
||||
Reference in New Issue
Block a user