T
TanStack2y ago
like-gold

Default Mutation Function best practices and Typescript

I've set up a default query function per the guide in the docs, but there's no guide on a default mutation function. I'd like to set on up so I don't have to get the auth token in each component, etc. Can I just do the following:
type MyMutationFunctionProps = {
apiPath: string
variables: object
}

const defaultMutationFn = async ({ apiPath, variables }: MyMutationFunctionProps) => {
console.log('defaultMutationFn', variables)
const { data } = await axios.post(`${BASE_URL}/${apiPath}`, variables, {
headers: { Authorization: `Bearer ${useAppState.getState().token}` },
})
return data
}
type MyMutationFunctionProps = {
apiPath: string
variables: object
}

const defaultMutationFn = async ({ apiPath, variables }: MyMutationFunctionProps) => {
console.log('defaultMutationFn', variables)
const { data } = await axios.post(`${BASE_URL}/${apiPath}`, variables, {
headers: { Authorization: `Bearer ${useAppState.getState().token}` },
})
return data
}
If that's appropriate, how do I resolve the defaultOptions.mutations.mutationFn typescript error?
Type '({ apiPath, variables }: MyMutationFunctionProps) => Promise<any>' is not assignable to type 'MutationFunction<unknown, unknown>'.
Types of parameters '__0' and 'variables' are incompatible.
Type 'unknown' is not assignable to type 'MyMutationFunctionProps'.ts(2322)
(property) MutationOptions<unknown, Error, unknown, unknown>.mutationFn?: MutationFunction<unknown, unknown> | undefined
Type '({ apiPath, variables }: MyMutationFunctionProps) => Promise<any>' is not assignable to type 'MutationFunction<unknown, unknown>'.
Types of parameters '__0' and 'variables' are incompatible.
Type 'unknown' is not assignable to type 'MyMutationFunctionProps'.ts(2322)
(property) MutationOptions<unknown, Error, unknown, unknown>.mutationFn?: MutationFunction<unknown, unknown> | undefined
7 Replies
flat-fuchsia
flat-fuchsia2y ago
You can't type the default mutation function like that because it's not guaranteed in TS that all your mutations will have that input. So either do a type assertion to bypass TS or validate at runtime with e.g. a zod schema
like-gold
like-goldOP2y ago
Aren't those types what determines the acceptable inputs for the mutation function? Then if somewhere in my code I pass something that doesn't match, TS will warn me? Apologies, still pretty new to TS.
flat-fuchsia
flat-fuchsia2y ago
The default mutation function doesn't set the types for all call-sides, no
like-gold
like-goldOP2y ago
I appreciate the replies. So what do people normally do for mutations throughout their app that's behind a JWT? Do they add the header each time they useMutation? perhaps just use a custom useAxios hook?
const useAxios = (apiPath: string) => {
const token = useAppState.getState().token

const headers = useMemo(() => {
return token ? { Authorization: `Bearer ${token}` } : {}
}, [token])

const mutationFn = useCallback(
async (body: object) => {
const response = await axios.post(`${BASE_URL}/${apiPath}`, body, { headers })
console.log({ response })
return response.data
},
[apiPath, headers]
)

return mutationFn
}
const useAxios = (apiPath: string) => {
const token = useAppState.getState().token

const headers = useMemo(() => {
return token ? { Authorization: `Bearer ${token}` } : {}
}, [token])

const mutationFn = useCallback(
async (body: object) => {
const response = await axios.post(`${BASE_URL}/${apiPath}`, body, { headers })
console.log({ response })
return response.data
},
[apiPath, headers]
)

return mutationFn
}
Then in my component it's just:
const mutationFn = useAxios('/materials/create')
const mutation = useMutation({ mutationFn })
const mutationFn = useAxios('/materials/create')
const mutation = useMutation({ mutationFn })
sunny-green
sunny-green2y ago
like-gold
like-goldOP2y ago
Well, since it would need to be configured based on the presence of the token (which changes, either way it'll need a custom hook, right?
flat-fuchsia
flat-fuchsia2y ago
it's usually best to keep these things out of react-query, on your api layer

Did you find this page helpful?