11import './mocks' ;
2- import { useState } from 'react' ;
2+ import { useRef , useState } from 'react' ;
33import { CommentData , PostData , baseUrl } from './mocks' ;
44import './App.css' ;
55import { HttpMutationBuilder , HttpQueryBuilder , useOperateOnTags } from 'react-query-builder' ;
@@ -8,22 +8,45 @@ import { queryClient } from './client';
88const baseQuery = new HttpQueryBuilder ( { queryClient } ) . withBaseUrl ( baseUrl ) ;
99const baseMutation = new HttpMutationBuilder ( { queryClient } ) . withBaseUrl ( baseUrl ) ;
1010
11- const resetMutation = baseMutation . withPath ( '/reset' ) . withConfig ( { invalidates : [ 'posts' as any , 'refreshable' ] } ) ;
11+ const resetMutation = baseMutation . withPath ( '/reset' ) . withConfig ( { invalidates : '*' } ) ;
1212
1313const postsQuery = baseQuery
1414 . withConfig ( { tags : 'refreshable' } )
1515 . withConfig ( { tags : { type : 'posts' as any , id : 'LIST' } } )
1616 . withPath ( '/posts' )
1717 . withData < PostData [ ] > ( ) ;
1818
19- const postQuery = baseQuery . withConfig ( { tags : 'refreshable' } ) . withPath ( '/posts/:id' ) . withData < PostData > ( ) ;
19+ const postQuery = baseQuery
20+ . withConfig ( { tags : 'refreshable' } )
21+ . withPath ( '/posts/:id' )
22+ . withData < PostData > ( )
23+ . withConfig ( {
24+ tags : ( ctx ) => [ { type : 'posts' as any , id : ctx . vars . params . id } ] ,
25+ } ) ;
2026
2127const commentsQuery = baseQuery
2228 . withConfig ( { tags : 'refreshable' } )
2329 . withPath ( '/comments' )
2430 . withSearch < { postId : number | null } > ( )
2531 . withData < CommentData [ ] > ( ) ;
2632
33+ const editPostMutation = baseMutation
34+ . withPath ( '/posts/:id' )
35+ . withVars ( { method : 'put' } )
36+ . withBody < Partial < PostData > > ( )
37+ . withConfig ( {
38+ invalidates : ( ) => [ { type : 'posts' as any , id : 'LIST' } ] ,
39+ optimisticUpdates : ( ctx ) => [
40+ {
41+ type : 'posts' as any ,
42+ id : ctx . vars . params . id ,
43+ updater ( ctx , target ) {
44+ return { ...target ! , ...ctx . vars . body } ;
45+ } ,
46+ } ,
47+ ] ,
48+ } ) ;
49+
2750const deletePostMutation = baseMutation
2851 . withVars ( { method : 'delete' } )
2952 . withPath ( '/posts/:id' )
@@ -68,8 +91,8 @@ function App() {
6891 < h2
6992 onClick = { ( ) => setPostId ( post . id ) }
7093 onMouseOver = { ( ) => {
71- postQuery . client . ensureData ( { params : { id : post . id } } ) ;
72- commentsQuery . client . ensureData ( { search : { postId : post . id } } ) ;
94+ postQuery . client . prefetch ( { params : { id : post . id } } ) ;
95+ commentsQuery . client . prefetch ( { search : { postId : post . id } } ) ;
7396 } }
7497 >
7598 { post . title }
@@ -94,18 +117,53 @@ function PostPage({ postId, onBack }: { postId: number; onBack: () => void }) {
94117 const post = postQuery . useQuery ( { params : { id : postId } } ) ;
95118 const comments = commentsQuery . useQuery ( { search : { postId : postId } } ) ;
96119
120+ const [ showEdit , setShowEdit ] = useState ( false ) ;
121+ const editPost = editPostMutation . useMutation ( ) ;
122+
123+ const titleRef = useRef < HTMLInputElement > ( null ) ;
124+ const bodyRef = useRef < HTMLTextAreaElement > ( null ) ;
125+
97126 return (
98127 < >
99- { post . isLoading ? (
100- 'Loading...'
101- ) : post . isError ? (
102- post . error . message
128+ { ! showEdit ? (
129+ < >
130+ { post . isLoading ? (
131+ 'Loading...'
132+ ) : post . isError ? (
133+ post . error . message
134+ ) : (
135+ < div >
136+ < h2 > { post . data ?. title } </ h2 >
137+ < p > { post . data ?. body } </ p >
138+ < button onClick = { onBack } > Back</ button >
139+ < button onClick = { ( ) => setShowEdit ( true ) } disabled = { editPost . isPending } >
140+ Edit post
141+ </ button >
142+ </ div >
143+ ) }
144+ </ >
103145 ) : (
104- < div >
105- < h2 > { post . data ?. title } </ h2 >
106- < p > { post . data ?. body } </ p >
107- < button onClick = { onBack } > Back</ button >
108- </ div >
146+ < >
147+ < h2 > Edit post</ h2 >
148+
149+ < input ref = { titleRef } defaultValue = { post . data ?. title } style = { { display : 'block' } } />
150+
151+ < textarea ref = { bodyRef } defaultValue = { post . data ?. body } style = { { display : 'block' , width : 400 } } />
152+
153+ < button
154+ onClick = { ( ) => {
155+ editPost . mutateAsync ( {
156+ params : { id : postId } ,
157+ body : { title : titleRef . current ! . value , body : bodyRef . current ! . value } ,
158+ } ) ;
159+
160+ setShowEdit ( false ) ;
161+ } }
162+ disabled = { editPost . isPending }
163+ >
164+ Save
165+ </ button >
166+ </ >
109167 ) }
110168
111169 < h3 > Comments</ h3 >
0 commit comments