Skip to content

Commit 855b202

Browse files
committed
return context from onMutate and define types on the onMutate function
1 parent d75ce8b commit 855b202

File tree

1 file changed

+24
-19
lines changed
  • examples/optimistic-updates-typescript/pages

1 file changed

+24
-19
lines changed

examples/optimistic-updates-typescript/pages/index.tsx

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,28 @@ export default function App() {
2323
)
2424
}
2525

26-
type TodoData = {
26+
type Todos = {
2727
items: readonly {
2828
id: string
2929
text: string
3030
}[]
3131
ts: number
3232
}
3333

34-
async function fetchTodos(): Promise<TodoData> {
34+
async function fetchTodos(): Promise<Todos> {
3535
const res = await axios.get('/api/data')
3636
return res.data
3737
}
3838

39-
function useTodos<TData = TodoData>(
40-
options?: UseQueryOptions<TData, AxiosError, TodoData>
39+
function useTodos<TData = Todos>(
40+
options?: UseQueryOptions<TData, AxiosError, Todos>
4141
) {
4242
return useQuery('todos', fetchTodos, options)
4343
}
4444

4545
function TodoCounter() {
46+
// subscribe only to changes in the 'data' prop, which will be the
47+
// amount of todos because of the select function
4648
const counterQuery = useTodos({
4749
select: data => data.items.length,
4850
notifyOnChangeProps: ['data'],
@@ -61,34 +63,37 @@ function Example() {
6163
const { isFetching, ...queryInfo } = useTodos()
6264

6365
const addTodoMutation = useMutation(
64-
(newTodo: string) => axios.post('/api/data', { text: newTodo }),
66+
newTodo => axios.post('/api/data', { text: newTodo }),
6567
{
66-
// Optimistically update the cache value on mutate, but store
67-
// the old value and return it so that it's accessible in case of
68-
// an error
69-
onMutate: async newTodo => {
68+
// When mutate is called:
69+
onMutate: async (newTodo: string) => {
7070
setText('')
71+
// Cancel any outgoing refetches (so they don't overwrite our optimistic update)
7172
await queryClient.cancelQueries('todos')
7273

73-
const previousValue = queryClient.getQueryData<TodoData>('todos')
74+
// Snapshot the previous value
75+
const previousTodos = queryClient.getQueryData<Todos>('todos')
7476

75-
if (previousValue) {
76-
queryClient.setQueryData<TodoData>('todos', {
77-
...previousValue,
77+
// Optimistically update to the new value
78+
if (previousTodos) {
79+
queryClient.setQueryData<Todos>('todos', {
80+
...previousTodos,
7881
items: [
79-
...previousValue.items,
82+
...previousTodos.items,
8083
{ id: Math.random().toString(), text: newTodo },
8184
],
8285
})
8386
}
8487

85-
return previousValue
88+
return { previousTodos }
8689
},
87-
// On failure, roll back to the previous value
88-
onError: (err, variables, previousValue) => {
89-
queryClient.setQueryData('todos', previousValue)
90+
// If the mutation fails, use the context returned from onMutate to roll back
91+
onError: (err, variables, context) => {
92+
if (context?.previousTodos) {
93+
queryClient.setQueryData<Todos>('todos', context.previousTodos)
94+
}
9095
},
91-
// After success or failure, refetch the todos query
96+
// Always refetch after error or success:
9297
onSettled: () => {
9398
queryClient.invalidateQueries('todos')
9499
},

0 commit comments

Comments
 (0)