forked from ava/use-http
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathuseMutation.ts
66 lines (56 loc) · 2.11 KB
/
useMutation.ts
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
import { useContext, useCallback } from 'react'
import useFetch from './useFetch'
import { FetchContext } from './FetchContext'
import { ReqBase } from './types'
import { invariant, isString, useURLRequiredInvariant } from './utils'
type ArrayDestructure<TData = any> = [
TData | undefined,
boolean,
Error | undefined,
(variables?: object) => Promise<any>,
]
interface ObjectDestructure<TData = any> extends ReqBase<TData> {
mutate: (variables?: object) => Promise<any>
}
type UseMutation<TData = any> = ArrayDestructure<TData> & ObjectDestructure<TData>
export const useMutation = <TData = any>(
urlOrMutation: string | TemplateStringsArray,
mutationArg?: string
): UseMutation<TData> => {
const context = useContext(FetchContext)
useURLRequiredInvariant(
!!context.url && Array.isArray(urlOrMutation),
'useMutation'
)
useURLRequiredInvariant(
!!context.url || (isString(urlOrMutation) && !mutationArg),
'useMutation',
'OR you need to do useMutation("https://example.com", `your graphql mutation`)'
)
// regular no context: useMutation('https://example.com', `graphql MUTATION`)
let url = urlOrMutation
let MUTATION = mutationArg as string
// tagged template literal with context: useMutation`graphql MUTATION`
if (Array.isArray(urlOrMutation) && context.url) {
invariant(
!mutationArg,
'You cannot have a 2nd argument when using tagged template literal syntax with useMutation.'
)
url = context.url
MUTATION = urlOrMutation[0]
// regular with context: useMutation(`graphql MUTATION`)
} else if (urlOrMutation && !mutationArg && context.url) {
url = context.url
MUTATION = urlOrMutation as string
}
const { loading, error, cache, ...request } = useFetch<TData>(url as string)
const mutate = useCallback(
(inputs?: object): Promise<any> => request.mutate(MUTATION, inputs),
[MUTATION, request]
)
const data = (request.data as TData & { data: any } || { data: undefined }).data
return Object.assign<ArrayDestructure<TData>, ObjectDestructure<TData>>(
[data, loading, error, mutate],
{ data, loading, error, mutate, cache }
)
}