Skip to content

Commit

Permalink
Merge pull request #132 from wobsoriano/useMutation
Browse files Browse the repository at this point in the history
  • Loading branch information
wobsoriano authored Dec 7, 2023
2 parents d430c64 + d2bff3b commit 49eb76f
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 8 deletions.
10 changes: 10 additions & 0 deletions docs/content/1.get-started/3.client.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,21 @@ As you can see, we passed `AppRouter` as a type argument of `createTRPCNuxtClien
<script setup lang="ts">
const { $client } = useNuxtApp()
// With composables
const getUser = await $client.getUser.useQuery('id_bilbo');
// => { data: { id: 'id_bilbo', name: 'Bilbo' }, pending: false, error: false };
const createUser = await $client.createUser.useMutation();
await createUser.mutate({ name: 'Frodo' });
// => { id: 'id_frodo', name: 'Frodo' };
// With vanilla
const bilbo = await $client.getUser.query('id_bilbo');
// => { id: 'id_bilbo', name: 'Bilbo' };
const frodo = await $client.createUser.mutate({ name: 'Frodo' });
// => { id: 'id_frodo', name: 'Frodo' };
</script>
Expand Down
13 changes: 7 additions & 6 deletions playground/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,21 @@ const { data } = useNuxtData(todosKey)
const { data: todos, pending, error, refresh } = await $client.todo.getTodos.useQuery()
const { mutate } = $client.todo.addTodo.useMutation()
const addTodo = async () => {
const title = Math.random().toString(36).slice(2, 7)
const newData = {
id: Date.now(),
userId: 69,
title,
completed: false
}
data.value.push(newData)
try {
const x = await $client.todo.addTodo.mutate(newData)
} catch (e) {
console.log(e)
}
const result = await mutate(newData)
data.value.push(result)
}
</script>

Expand Down
41 changes: 40 additions & 1 deletion src/client/decorationProxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { type inferRouterProxyClient } from '@trpc/client'
import { type AnyRouter } from '@trpc/server'
import { createRecursiveProxy } from '@trpc/server/shared'
// @ts-expect-error: Nuxt auto-imports
import { getCurrentInstance, onScopeDispose, useAsyncData, unref, isRef } from '#imports'
import { getCurrentInstance, onScopeDispose, useAsyncData, unref, ref, isRef, toRaw } from '#imports'
import { getQueryKeyInternal } from './getQueryKey'

export function createNuxtProxyDecoration<TRouter extends AnyRouter> (name: string, client: inferRouterProxyClient<TRouter>) {
Expand Down Expand Up @@ -52,6 +52,45 @@ export function createNuxtProxyDecoration<TRouter extends AnyRouter> (name: stri
lazy: isLazy
})
}

if (lastArg === 'useMutation') {
const { trpc, queryKey: customQueryKey, ...asyncDataOptions } = otherOptions || {} as any
// Payload will be set by the `mutate` function and used by `useAsyncData`.
const payload = ref(null)

let controller: AbortController

if (trpc?.abortOnUnmount) {
if (getCurrentInstance()) {
onScopeDispose(() => {
controller?.abort?.()
})
}
controller = typeof AbortController !== 'undefined' ? new AbortController() : {} as AbortController
}

const queryKey = customQueryKey || getQueryKeyInternal(path, undefined)

const asyncData = useAsyncData(queryKey, () => (client as any)[path].mutate(payload.value, {
signal: controller?.signal,
...trpc
}), {
...asyncDataOptions,
immediate: false
})

// eslint-disable-next-line no-inner-declarations
async function mutate (input: any) {
payload.value = input
await asyncData.execute()
return toRaw(asyncData.data.value)
}

return {
mutate,
...asyncData
}
}

return (client as any)[path][lastArg](...args)
})
Expand Down
12 changes: 11 additions & 1 deletion src/client/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import type {
KeysOf,
PickFrom,
} from 'nuxt/dist/app/composables/asyncData'
import type { Ref } from 'vue'
import type { Ref, UnwrapRef } from 'vue'

interface TRPCRequestOptions extends _TRPCRequestOptions {
abortOnUnmount?: boolean
Expand Down Expand Up @@ -87,6 +87,16 @@ export type DecorateProcedure<
query: Resolver<TProcedure>
} : TProcedure extends AnyMutationProcedure ? {
mutate: Resolver<TProcedure>
useMutation: <
ResT = inferTransformedProcedureOutput<TProcedure>,
DataE = TRPCClientErrorLike<TProcedure>,
DataT = ResT,
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
>(
opts?: Omit<AsyncDataOptions<ResT, DataT, PickKeys>, 'lazy'> & {
trpc?: TRPCRequestOptions
},
) => AsyncData<PickFrom<DataT, PickKeys> | null, DataE> & { mutate: (input: inferProcedureInput<TProcedure>) => Promise<UnwrapRef<AsyncData<PickFrom<DataT, PickKeys> | null, DataE>['data']>> },
} : TProcedure extends AnySubscriptionProcedure ? {
subscribe: SubscriptionResolver<TProcedure, TRouter>
} : never
Expand Down

1 comment on commit 49eb76f

@vercel
Copy link

@vercel vercel bot commented on 49eb76f Dec 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

trpc-nuxt – ./

trpc-nuxt-git-main-wobsoriano.vercel.app
trpc-nuxt.vercel.app
trpc-nuxt-wobsoriano.vercel.app

Please sign in to comment.