@@ -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
4545function 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