diff --git a/docs/config.json b/docs/config.json
index 556ed2b67d..aa16e1f47f 100644
--- a/docs/config.json
+++ b/docs/config.json
@@ -526,6 +526,35 @@
}
]
},
+ {
+ "label": "svelte",
+ "children": [
+ {
+ "label": "Queries",
+ "to": "framework/svelte/guides/queries"
+ },
+ {
+ "label": "Network Mode",
+ "to": "framework/svelte/guides/network-mode"
+ },
+ {
+ "label": "Mutations",
+ "to": "framework/svelte/guides/mutations"
+ },
+ {
+ "label": "Invalidations from Mutations",
+ "to": "framework/svelte/guides/invalidations-from-mutations"
+ },
+ {
+ "label": "Optimistic Updates",
+ "to": "framework/svelte/guides/optimistic-updates"
+ },
+ {
+ "label": "Query Cancellation",
+ "to": "framework/svelte/guides/query-cancellation"
+ }
+ ]
+ },
{
"label": "vue",
"children": [
diff --git a/docs/framework/svelte/guides/invalidations-from-mutations.md b/docs/framework/svelte/guides/invalidations-from-mutations.md
new file mode 100644
index 0000000000..3e3c4bb4ee
--- /dev/null
+++ b/docs/framework/svelte/guides/invalidations-from-mutations.md
@@ -0,0 +1,14 @@
+---
+id: invalidations-from-mutations
+title: Invalidations from Mutations
+ref: docs/framework/react/guides/invalidations-from-mutations.md
+replace:
+ {
+ 'React': 'Svelte',
+ '@tanstack/react-query': '@tanstack/svelte-query',
+ 'useMutation[(]': 'createMutation(() => ',
+ 'useMutation': 'createMutation',
+ 'useQuery[(]': 'createQuery(() => ',
+ 'hook': 'function',
+ }
+---
diff --git a/docs/framework/svelte/guides/mutations.md b/docs/framework/svelte/guides/mutations.md
new file mode 100644
index 0000000000..26d053cdf6
--- /dev/null
+++ b/docs/framework/svelte/guides/mutations.md
@@ -0,0 +1,263 @@
+---
+id: mutations
+title: Mutations
+ref: docs/framework/react/guides/mutations.md
+replace: { 'useMutation': 'createMutation', 'hook': 'function' }
+---
+
+[//]: # 'Example'
+
+```svelte
+
+
+
+ {#if mutation.isPending}
+
Adding todo...
+ {:else if mutation.isError}
+
An error occurred: {mutation.error.message}
+ {:else if mutation.isSuccess}
+
Todo added!
+ {/if}
+
+
+```
+
+[//]: # 'Example'
+[//]: # 'Info1'
+[//]: # 'Info1'
+[//]: # 'Example2'
+[//]: # 'Example2'
+[//]: # 'Example3'
+
+```svelte
+
+
+
+```
+
+[//]: # 'Example3'
+[//]: # 'Example4'
+
+```ts
+createMutation(() => ({
+ mutationFn: addTodo,
+ onMutate: (variables, context) => {
+ // A mutation is about to happen!
+
+ // Optionally return a result containing data to use when for example rolling back
+ return { id: 1 }
+ },
+ onError: (error, variables, onMutateResult, context) => {
+ // An error happened!
+ console.log(`rolling back optimistic update with id ${onMutateResult.id}`)
+ },
+ onSuccess: (data, variables, onMutateResult, context) => {
+ // Boom baby!
+ },
+ onSettled: (data, error, variables, onMutateResult, context) => {
+ // Error or success... doesn't matter!
+ },
+}))
+```
+
+[//]: # 'Example4'
+[//]: # 'Example5'
+
+```ts
+createMutation(() => ({
+ mutationFn: addTodo,
+ onSuccess: async () => {
+ console.log("I'm first!")
+ },
+ onSettled: async () => {
+ console.log("I'm second!")
+ },
+}))
+```
+
+[//]: # 'Example5'
+[//]: # 'Example6'
+
+```ts
+const mutation = createMutation(() => ({
+ mutationFn: addTodo,
+ onSuccess: (data, variables, onMutateResult, context) => {
+ // I will fire first
+ },
+ onError: (error, variables, onMutateResult, context) => {
+ // I will fire first
+ },
+ onSettled: (data, error, variables, onMutateResult, context) => {
+ // I will fire first
+ },
+}))
+
+mutation.mutate(todo, {
+ onSuccess: (data, variables, onMutateResult, context) => {
+ // I will fire second!
+ },
+ onError: (error, variables, onMutateResult, context) => {
+ // I will fire second!
+ },
+ onSettled: (data, error, variables, onMutateResult, context) => {
+ // I will fire second!
+ },
+})
+```
+
+[//]: # 'Example6'
+[//]: # 'Example7'
+
+```ts
+const mutation = createMutation(() => ({
+ mutationFn: addTodo,
+ onSuccess: (data, variables, onMutateResult, context) => {
+ // Will be called 3 times
+ },
+}))
+
+const todos = ['Todo 1', 'Todo 2', 'Todo 3']
+todos.forEach((todo) => {
+ mutation.mutate(todo, {
+ onSuccess: (data, variables, onMutateResult, context) => {
+ // Will execute only once, for the last mutation (Todo 3),
+ // regardless which mutation resolves first
+ },
+ })
+})
+```
+
+[//]: # 'Example7'
+[//]: # 'Example8'
+
+```ts
+const mutation = createMutation(() => ({ mutationFn: addTodo }))
+
+try {
+ const todo = await mutation.mutateAsync(todo)
+ console.log(todo)
+} catch (error) {
+ console.error(error)
+} finally {
+ console.log('done')
+}
+```
+
+[//]: # 'Example8'
+[//]: # 'Example9'
+
+```ts
+const mutation = createMutation(() => ({
+ mutationFn: addTodo,
+ retry: 3,
+}))
+```
+
+[//]: # 'Example9'
+[//]: # 'Example10'
+
+```ts
+const queryClient = new QueryClient()
+
+// Define the "addTodo" mutation
+queryClient.setMutationDefaults(['addTodo'], {
+ mutationFn: addTodo,
+ onMutate: async (variables, context) => {
+ // Cancel current queries for the todos list
+ await context.client.cancelQueries({ queryKey: ['todos'] })
+
+ // Create optimistic todo
+ const optimisticTodo = { id: uuid(), title: variables.title }
+
+ // Add optimistic todo to todos list
+ context.client.setQueryData(['todos'], (old) => [...old, optimisticTodo])
+
+ // Return a result with the optimistic todo
+ return { optimisticTodo }
+ },
+ onSuccess: (result, variables, onMutateResult, context) => {
+ // Replace optimistic todo in the todos list with the result
+ context.client.setQueryData(['todos'], (old) =>
+ old.map((todo) =>
+ todo.id === onMutateResult.optimisticTodo.id ? result : todo,
+ ),
+ )
+ },
+ onError: (error, variables, onMutateResult, context) => {
+ // Remove optimistic todo from the todos list
+ context.client.setQueryData(['todos'], (old) =>
+ old.filter((todo) => todo.id !== onMutateResult.optimisticTodo.id),
+ )
+ },
+ retry: 3,
+})
+
+// Start mutation in some component:
+const mutation = createMutation(() => ({ mutationKey: ['addTodo'] }))
+mutation.mutate({ title: 'title' })
+
+// If the mutation has been paused because the device is for example offline,
+// Then the paused mutation can be dehydrated when the application quits:
+const state = dehydrate(queryClient)
+
+// The mutation can then be hydrated again when the application is started:
+hydrate(queryClient, state)
+
+// Resume the paused mutations:
+queryClient.resumePausedMutations()
+```
+
+[//]: # 'Example10'
+[//]: # 'PersistOfflineIntro'
+[//]: # 'PersistOfflineIntro'
+[//]: # 'Example11'
+[//]: # 'Example11'
+[//]: # 'OfflineExampleLink'
+[//]: # 'OfflineExampleLink'
+[//]: # 'ExampleScopes'
+
+```ts
+const mutation = createMutation(() => ({
+ mutationFn: addTodo,
+ scope: {
+ id: 'todo',
+ },
+}))
+```
+
+[//]: # 'ExampleScopes'
+[//]: # 'Materials'
+[//]: # 'Materials'
diff --git a/docs/framework/svelte/guides/network-mode.md b/docs/framework/svelte/guides/network-mode.md
new file mode 100644
index 0000000000..e773e73ff0
--- /dev/null
+++ b/docs/framework/svelte/guides/network-mode.md
@@ -0,0 +1,5 @@
+---
+id: network-mode
+title: Network Mode
+ref: docs/framework/react/guides/network-mode.md
+---
diff --git a/docs/framework/svelte/guides/optimistic-updates.md b/docs/framework/svelte/guides/optimistic-updates.md
new file mode 100644
index 0000000000..b63ca89f5d
--- /dev/null
+++ b/docs/framework/svelte/guides/optimistic-updates.md
@@ -0,0 +1,149 @@
+---
+id: optimistic-updates
+title: Optimistic Updates
+ref: docs/framework/react/guides/optimistic-updates.md
+replace:
+ { 'React': 'Svelte', 'useMutation': 'createMutation', 'hook': 'function' }
+---
+
+[//]: # 'ExampleUI1'
+
+```ts
+const addTodoMutation = createMutation(() => ({
+ mutationFn: (newTodo: string) => axios.post('/api/data', { text: newTodo }),
+ // make sure to _return_ the Promise from the query invalidation
+ // so that the mutation stays in `pending` state until the refetch is finished
+ onSettled: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
+}))
+```
+
+[//]: # 'ExampleUI1'
+[//]: # 'ExampleUI2'
+
+```svelte
+
+ {#each todoQuery.data as todo}
+ - {todo.text}
+ {/each}
+ {#if addTodoMutation.isPending}
+ - {addTodoMutation.variables}
+ {/if}
+
+```
+
+[//]: # 'ExampleUI2'
+[//]: # 'ExampleUI3'
+
+```svelte
+{#if addTodoMutation.isError}
+
+ {addTodoMutation.variables}
+
+
+{/if}
+```
+
+[//]: # 'ExampleUI3'
+[//]: # 'ExampleUI4'
+
+```ts
+// somewhere in your app
+const mutation = createMutation(() => ({
+ mutationFn: (newTodo: string) => axios.post('/api/data', { text: newTodo }),
+ onSettled: () => queryClient.invalidateQueries({ queryKey: ['todos'] }),
+ mutationKey: ['addTodo'],
+}))
+
+// access variables somewhere else
+const variables = useMutationState({
+ filters: { mutationKey: ['addTodo'], status: 'pending' },
+ select: (mutation) => mutation.state.variables,
+})
+```
+
+[//]: # 'ExampleUI4'
+[//]: # 'Example'
+
+```ts
+const queryClient = useQueryClient()
+
+createMutation(() => ({
+ mutationFn: updateTodo,
+ // When mutate is called:
+ onMutate: async (newTodo, context) => {
+ // Cancel any outgoing refetches
+ // (so they don't overwrite our optimistic update)
+ await context.client.cancelQueries({ queryKey: ['todos'] })
+
+ // Snapshot the previous value
+ const previousTodos = context.client.getQueryData(['todos'])
+
+ // Optimistically update to the new value
+ context.client.setQueryData(['todos'], (old) => [...(old ?? []), newTodo])
+
+ // Return a result with the snapshotted value
+ return { previousTodos }
+ },
+ // If the mutation fails,
+ // use the result returned from onMutate to roll back
+ onError: (err, newTodo, onMutateResult, context) => {
+ context.client.setQueryData(['todos'], onMutateResult.previousTodos)
+ },
+ // Always refetch after error or success:
+ onSettled: (data, error, variables, onMutateResult, context) =>
+ context.client.invalidateQueries({ queryKey: ['todos'] }),
+}))
+```
+
+[//]: # 'Example'
+[//]: # 'Example2'
+
+```ts
+createMutation(() => ({
+ mutationFn: updateTodo,
+ // When mutate is called:
+ onMutate: async (newTodo, context) => {
+ // Cancel any outgoing refetches
+ // (so they don't overwrite our optimistic update)
+ await context.client.cancelQueries({ queryKey: ['todos', newTodo.id] })
+
+ // Snapshot the previous value
+ const previousTodo = context.client.getQueryData(['todos', newTodo.id])
+
+ // Optimistically update to the new value
+ context.client.setQueryData(['todos', newTodo.id], newTodo)
+
+ // Return a result with the previous and new todo
+ return { previousTodo, newTodo }
+ },
+ // If the mutation fails, use the result we returned above
+ onError: (err, newTodo, onMutateResult, context) => {
+ context.client.setQueryData(
+ ['todos', onMutateResult?.newTodo.id],
+ onMutateResult?.previousTodo,
+ )
+ },
+ // Always refetch after error or success:
+ onSettled: (newTodo, error, variables, onMutateResult, context) =>
+ context.client.invalidateQueries({ queryKey: ['todos', variables.id] }),
+}))
+```
+
+[//]: # 'Example2'
+[//]: # 'Example3'
+
+```ts
+createMutation(() => ({
+ mutationFn: updateTodo,
+ // ...
+ onSettled: async (newTodo, error, variables, onMutateResult, context) => {
+ if (error) {
+ // do something
+ }
+ },
+}))
+```
+
+[//]: # 'Example3'
diff --git a/docs/framework/svelte/guides/queries.md b/docs/framework/svelte/guides/queries.md
new file mode 100644
index 0000000000..52f4b865ff
--- /dev/null
+++ b/docs/framework/svelte/guides/queries.md
@@ -0,0 +1,90 @@
+---
+id: queries
+title: Queries
+ref: docs/framework/react/guides/queries.md
+replace:
+ {
+ 'React': 'Svelte',
+ 'react-query': 'svelte-query',
+ 'or custom hooks': '',
+ 'the `useQuery` hook': '`createQuery`',
+ 'useQuery': 'createQuery',
+ }
+---
+
+[//]: # 'Example'
+
+```svelte
+
+```
+
+[//]: # 'Example'
+[//]: # 'Example2'
+
+```ts
+const todosQuery = createQuery(() => ({
+ queryKey: ['todos'],
+ queryFn: fetchTodoList,
+}))
+```
+
+[//]: # 'Example2'
+[//]: # 'Example3'
+
+```svelte
+
+
+
+ {#if todosQuery.isPending}
+
Loading...
+ {:else if todosQuery.isError}
+
Error: {todosQuery.error.message}
+ {:else if todosQuery.isSuccess}
+ {#each todosQuery.data as todo}
+
{todo.title}
+ {/each}
+ {/if}
+
+```
+
+[//]: # 'Example3'
+
+If booleans aren't your thing, you can always use the `status` state as well:
+
+[//]: # 'Example4'
+
+```svelte
+
+
+
+ {#if todosQuery.status === 'pending'}
+
Loading...
+ {:else if todosQuery.status === 'error'}
+
Error: {todosQuery.error.message}
+ {:else if todosQuery.status === 'success'}
+ {#each todosQuery.data as todo}
+
{todo.title}
+ {/each}
+ {/if}
+
+```
+
+[//]: # 'Example4'
+[//]: # 'Materials'
+[//]: # 'Materials'
diff --git a/docs/framework/svelte/guides/query-cancellation.md b/docs/framework/svelte/guides/query-cancellation.md
new file mode 100644
index 0000000000..b38323ca3d
--- /dev/null
+++ b/docs/framework/svelte/guides/query-cancellation.md
@@ -0,0 +1,160 @@
+---
+id: query-cancellation
+title: Query Cancellation
+ref: docs/framework/react/guides/query-cancellation.md
+replace:
+ {
+ '@tanstack/react-query': '@tanstack/svelte-query',
+ 'useQuery[(]': 'createQuery(() => ',
+ }
+---
+
+[//]: # 'Example'
+
+```ts
+const todosQuery = createQuery(() => ({
+ queryKey: ['todos'],
+ queryFn: async ({ signal }) => {
+ const todosResponse = await fetch('/todos', {
+ // Pass the signal to one fetch
+ signal,
+ })
+ const todos = await todosResponse.json()
+
+ const todoDetails = todos.map(async ({ details }) => {
+ const response = await fetch(details, {
+ // Or pass it to several
+ signal,
+ })
+ return response.json()
+ })
+
+ return Promise.all(todoDetails)
+ },
+}))
+```
+
+[//]: # 'Example'
+[//]: # 'Example2'
+
+```ts
+import axios from 'axios'
+
+const todosQuery = createQuery(() => ({
+ queryKey: ['todos'],
+ queryFn: ({ signal }) =>
+ axios.get('/todos', {
+ // Pass the signal to `axios`
+ signal,
+ }),
+}))
+```
+
+[//]: # 'Example2'
+[//]: # 'Example3'
+
+```ts
+import axios from 'axios'
+
+const todosQuery = createQuery(() => ({
+ queryKey: ['todos'],
+ queryFn: ({ signal }) => {
+ // Create a new CancelToken source for this request
+ const CancelToken = axios.CancelToken
+ const source = CancelToken.source()
+
+ const promise = axios.get('/todos', {
+ // Pass the source token to your request
+ cancelToken: source.token,
+ })
+
+ // Cancel the request if TanStack Query signals to abort
+ signal?.addEventListener('abort', () => {
+ source.cancel('Query was cancelled by TanStack Query')
+ })
+
+ return promise
+ },
+}))
+```
+
+[//]: # 'Example3'
+[//]: # 'Example4'
+
+```ts
+const todosQuery = createQuery(() => ({
+ queryKey: ['todos'],
+ queryFn: ({ signal }) => {
+ return new Promise((resolve, reject) => {
+ var oReq = new XMLHttpRequest()
+ oReq.addEventListener('load', () => {
+ resolve(JSON.parse(oReq.responseText))
+ })
+ signal?.addEventListener('abort', () => {
+ oReq.abort()
+ reject()
+ })
+ oReq.open('GET', '/todos')
+ oReq.send()
+ })
+ },
+}))
+```
+
+[//]: # 'Example4'
+[//]: # 'Example5'
+
+```ts
+const client = new GraphQLClient(endpoint)
+
+const todosQuery = createQuery(() => ({
+ queryKey: ['todos'],
+ queryFn: ({ signal }) => {
+ client.request({ document: query, signal })
+ },
+}))
+```
+
+[//]: # 'Example5'
+[//]: # 'Example6'
+
+```ts
+const todosQuery = createQuery(() => ({
+ queryKey: ['todos'],
+ queryFn: ({ signal }) => {
+ const client = new GraphQLClient(endpoint, {
+ signal,
+ })
+ return client.request(query, variables)
+ },
+}))
+```
+
+[//]: # 'Example6'
+[//]: # 'Example7'
+
+```svelte
+
+
+
+```
+
+[//]: # 'Example7'
+[//]: # 'Limitations'
+[//]: # 'Limitations'