-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
/
Copy path+page.svelte
129 lines (113 loc) · 3.1 KB
/
+page.svelte
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
<script lang="ts">
import '../app.css'
import {
useQueryClient,
createQuery,
createMutation,
} from '@tanstack/svelte-query'
type Todo = {
id: string
text: string
}
type Todos = {
items: readonly Todo[]
ts: number
}
let text = $state<string>('')
const client = useQueryClient()
const endpoint = '/api/data'
const fetchTodos = async (): Promise<Todos> =>
await fetch(endpoint).then((r) => r.json())
const createTodo = async (text: string): Promise<Todo> =>
await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
text,
}),
}).then((res) => res.json())
const todos = createQuery<Todos>(() => ({
queryKey: ['optimistic'],
queryFn: fetchTodos,
}))
const addTodoMutation = createMutation(() => ({
mutationFn: createTodo,
onMutate: async (newTodo: string) => {
text = ''
// Cancel any outgoing refetches (so they don't overwrite our optimistic update)
await client.cancelQueries({ queryKey: ['optimistic'] })
// Snapshot the previous value
const previousTodos = client.getQueryData<Todos>(['optimistic'])
// Optimistically update to the new value
if (previousTodos) {
client.setQueryData<Todos>(['optimistic'], {
...previousTodos,
items: [
...previousTodos.items,
{ id: Math.random().toString(), text: newTodo },
],
})
}
return { previousTodos }
},
// If the mutation fails, use the context returned from onMutate to roll back
onError: (err: any, variables: any, context: any) => {
if (context?.previousTodos) {
client.setQueryData<Todos>(['optimistic'], context.previousTodos)
}
},
// Always refetch after error or success:
onSettled: () => {
client.invalidateQueries({ queryKey: ['optimistic'] })
},
}))
</script>
<h1>Optimistic Updates</h1>
<p>
In this example, new items can be created using a mutation. The new item will
be optimistically added to the list in hopes that the server accepts the item.
If it does, the list is refetched with the true items from the list. Every now
and then, the mutation may fail though. When that happens, the previous list
of items is restored and the list is again refetched from the server.
</p>
<form
onsubmit={(e) => {
e.preventDefault()
e.stopPropagation()
addTodoMutation.mutate(text)
}}
>
<div>
<input type="text" bind:value={text} />
<button disabled={addTodoMutation.isPending}>Create</button>
</div>
</form>
{#if todos.isPending}
Loading...
{/if}
{#if todos.error}
An error has occurred:
{todos.error.message}
{/if}
{#if todos.isSuccess}
<div class="mb-4">
Updated At: {new Date(todos.data.ts).toLocaleTimeString()}
</div>
<ul>
{#each todos.data.items as todo}
<li>{todo.text}</li>
{/each}
</ul>
{/if}
{#if todos.isFetching}
<div style="color:darkgreen; font-weight:700">
'Background Updating...' : ' '
</div>
{/if}
<style>
li {
text-align: left;
}
</style>