@@ -89,104 +89,161 @@ export const useCreate = <
8989 const dataProvider = useDataProvider ( ) ;
9090 const queryClient = useQueryClient ( ) ;
9191
92- const { mutationMode = 'pessimistic' , ...mutationOptions } = options ;
92+ const {
93+ mutationMode = 'pessimistic' ,
94+ getMutateWithMiddlewares,
95+ ...mutationOptions
96+ } = options ;
9397
94- const updateCache = useEvent (
95- (
96- resource : string ,
97- { data, meta } : Partial < CreateParams < RecordType > > ,
98- { mutationMode } : { mutationMode : MutationMode } ,
99- result : ResultRecordType
100- ) => {
101- const id = mutationMode === 'pessimistic' ? result . id : data ?. id ;
102- if ( ! id ) {
103- return undefined ;
104- }
105- // hack: only way to tell react-query not to fetch this query for the next 5 seconds
106- // because setQueryData doesn't accept a stale time option
107- const now = Date . now ( ) ;
108- const updatedAt =
109- mutationMode === 'undoable' ? now + 5 * 1000 : now ;
110- // Stringify and parse the data to remove undefined values.
111- // If we don't do this, an update with { id: undefined } as payload
112- // would remove the id from the record, which no real data provider does.
113- const clonedData = JSON . parse (
114- JSON . stringify ( mutationMode === 'pessimistic' ? result : data )
115- ) ;
98+ const dataProviderCreate = useEvent ( ( resource : string , params ) =>
99+ dataProvider
100+ . create <
101+ RecordType ,
102+ ResultRecordType
103+ > ( resource , params as CreateParams < RecordType > )
104+ . then ( ( { data } ) => data )
105+ ) ;
116106
117- queryClient . setQueryData (
118- [ resource , 'getOne' , { id : String ( id ) , meta } ] ,
119- ( record : RecordType ) => ( { ...record , ...clonedData } ) ,
120- { updatedAt }
121- ) ;
107+ const [ mutate , mutationResult ] = useMutationWithMutationMode <
108+ MutationError ,
109+ ResultRecordType ,
110+ UseCreateMutateParams < RecordType >
111+ > (
112+ { resource, ...params } ,
113+ {
114+ ...mutationOptions ,
115+ mutationKey : [ resource , 'create' , params ] ,
116+ mutationMode,
117+ mutationFn : ( { resource, ...params } ) => {
118+ if ( resource == null ) {
119+ throw new Error ( 'useCreate mutation requires a resource' ) ;
120+ }
121+ if ( params == null ) {
122+ throw new Error ( 'useCreate mutation requires parameters' ) ;
123+ }
124+ return dataProviderCreate ( resource , params ) ;
125+ } ,
126+ updateCache : (
127+ { resource, ...params } ,
128+ { mutationMode } ,
129+ result
130+ ) => {
131+ const id =
132+ mutationMode === 'pessimistic'
133+ ? result ?. id
134+ : params . data ?. id ;
135+ if ( ! id ) {
136+ return undefined ;
137+ }
138+ // hack: only way to tell react-query not to fetch this query for the next 5 seconds
139+ // because setQueryData doesn't accept a stale time option
140+ const now = Date . now ( ) ;
141+ const updatedAt =
142+ mutationMode === 'undoable' ? now + 5 * 1000 : now ;
143+ // Stringify and parse the data to remove undefined values.
144+ // If we don't do this, an update with { id: undefined } as payload
145+ // would remove the id from the record, which no real data provider does.
146+ const clonedData = JSON . parse (
147+ JSON . stringify (
148+ mutationMode === 'pessimistic' ? result : params . data
149+ )
150+ ) ;
122151
123- return clonedData ;
124- }
125- ) ;
152+ queryClient . setQueryData (
153+ [ resource , 'getOne' , { id : String ( id ) , meta : params . meta } ] ,
154+ ( record : RecordType ) => ( { ...record , ...clonedData } ) ,
155+ { updatedAt }
156+ ) ;
126157
127- const getSnapshot = useEvent (
128- (
129- resource : string ,
130- { data, meta } : Partial < CreateParams < RecordType > > ,
131- { mutationMode } : { mutationMode : MutationMode }
132- ) => {
133- const queryKeys : any [ ] = [
134- [ resource , 'getList' ] ,
135- [ resource , 'getInfiniteList' ] ,
136- [ resource , 'getMany' ] ,
137- [ resource , 'getManyReference' ] ,
138- ] ;
158+ return clonedData ;
159+ } ,
160+ getSnapshot : ( { resource, ...params } , { mutationMode } ) => {
161+ const queryKeys : any [ ] = [
162+ [ resource , 'getList' ] ,
163+ [ resource , 'getInfiniteList' ] ,
164+ [ resource , 'getMany' ] ,
165+ [ resource , 'getManyReference' ] ,
166+ ] ;
139167
140- if ( mutationMode !== 'pessimistic' && data ?. id ) {
141- queryKeys . push ( [
142- resource ,
143- 'getOne' ,
144- { id : String ( data . id ) , meta } ,
145- ] ) ;
146- }
168+ if ( mutationMode !== 'pessimistic' && params . data ?. id ) {
169+ queryKeys . push ( [
170+ resource ,
171+ 'getOne' ,
172+ { id : String ( params . data . id ) , meta : params . meta } ,
173+ ] ) ;
174+ }
147175
148- /**
149- * Snapshot the previous values via queryClient.getQueriesData()
150- *
151- * The snapshotData ref will contain an array of tuples [query key, associated data]
152- *
153- * @example
154- * [
155- * [['posts', 'getOne', { id: '1' }], { id: 1, title: 'Hello' }],
156- * [['posts', 'getList'], { data: [{ id: 1, title: 'Hello' }], total: 1 }],
157- * [['posts', 'getMany'], [{ id: 1, title: 'Hello' }]],
158- * ]
159- *
160- * @see https://react-query-v3.tanstack.com/reference/QueryClient#queryclientgetqueriesdata
161- */
162- const snapshot = queryKeys . reduce (
163- ( prev , queryKey ) =>
164- prev . concat ( queryClient . getQueriesData ( { queryKey } ) ) ,
165- [ ] as Snapshot
166- ) ;
176+ /**
177+ * Snapshot the previous values via queryClient.getQueriesData()
178+ *
179+ * The snapshotData ref will contain an array of tuples [query key, associated data]
180+ *
181+ * @example
182+ * [
183+ * [['posts', 'getOne', { id: '1' }], { id: 1, title: 'Hello' }],
184+ * [['posts', 'getList'], { data: [{ id: 1, title: 'Hello' }], total: 1 }],
185+ * [['posts', 'getMany'], [{ id: 1, title: 'Hello' }]],
186+ * ]
187+ *
188+ * @see https://react-query-v3.tanstack.com/reference/QueryClient#queryclientgetqueriesdata
189+ */
190+ const snapshot = queryKeys . reduce (
191+ ( prev , queryKey ) =>
192+ prev . concat ( queryClient . getQueriesData ( { queryKey } ) ) ,
193+ [ ] as Snapshot
194+ ) ;
167195
168- return snapshot ;
196+ return snapshot ;
197+ } ,
198+ getMutateWithMiddlewares : mutationFn => args => {
199+ // This is necessary to avoid breaking changes in useCreate:
200+ // The mutation function must have the same signature as before (resource, params) and not ({ resource, params })
201+ if ( getMutateWithMiddlewares ) {
202+ const { resource, ...params } = args ;
203+ return getMutateWithMiddlewares (
204+ dataProviderCreate . bind ( dataProvider )
205+ ) ( resource , params ) ;
206+ }
207+ return mutationFn ( args ) ;
208+ } ,
209+ onUndo : ( { resource, data, meta } ) => {
210+ queryClient . removeQueries ( {
211+ queryKey : [
212+ resource ,
213+ 'getOne' ,
214+ { id : String ( data ?. id ) , meta } ,
215+ ] ,
216+ exact : true ,
217+ } ) ;
218+ } ,
169219 }
170220 ) ;
171221
172- const onUndo = useEvent (
173- ( resource : string , { data, meta } : CreateParams < RecordType > ) => {
174- queryClient . removeQueries ( {
175- queryKey : [ resource , 'getOne' , { id : String ( data . id ) , meta } ] ,
176- exact : true ,
177- } ) ;
222+ const create = useEvent (
223+ (
224+ callTimeResource : string | undefined = resource ,
225+ callTimeParams : Partial < CreateParams < RecordType > > = { } ,
226+ callTimeOptions : MutateOptions <
227+ ResultRecordType ,
228+ MutationError ,
229+ Partial < UseCreateMutateParams < RecordType > > ,
230+ unknown
231+ > & {
232+ mutationMode ?: MutationMode ;
233+ returnPromise ?: boolean ;
234+ } = { }
235+ ) => {
236+ return mutate (
237+ {
238+ resource : callTimeResource ,
239+ ...callTimeParams ,
240+ } ,
241+ callTimeOptions
242+ ) ;
178243 }
179244 ) ;
180245
181- return useMutationWithMutationMode ( resource , params , {
182- ...mutationOptions ,
183- mutationKey : [ resource , 'create' , params ] ,
184- mutationMode,
185- mutationFn : dataProvider . create . bind ( dataProvider ) ,
186- updateCache,
187- getSnapshot,
188- onUndo,
189- } ) ;
246+ return [ create , mutationResult ] ;
190247} ;
191248
192249export interface UseCreateMutateParams <
0 commit comments