Open cannap opened 1 year ago
I am also having the same problem. In fact, even using the example in the playground errors out with TypeError: client[procedureType] is not a function
. I am unable to use trpc with this module. Documentation is also very lacking.
Edit: after further testing, I now understand slightly better. I can use trpc to retrieve data, but still any components that use the client just produce errors in the devtools, which effectively means I just can't use it because I really need my devtools to work.
edit edit: This only seems to be a problem when you access the client from top level of component. If you move the logic inside of onMounted like so:
import type { AppRouter } from '@/server/trpc/routers'
const hello = ref<inferRouterOutputs<AppRouter>['hello'] | null>(null)
onMounted(async () => {
const { $client } = useNuxtApp()
const { data: todos, pending, error } = await $client.hello.useQuery({ text: 'client' })
hello.value = todos.value
})
then everything is fine. The only problem now is that it makes the other refs like pending basically useless. If you were to create a new ref outside of onmounted to hold the value of 'pending', you would only be able to set the value of pending after the await statement, at which point you would no longer be pending, unless I am missing something here? Instructions unclear. Please advise.
Edit Edit Edit: OK SO... I have narrowed down the cause/solution, but it's a weird one. This code results in an error at runtime:
const { $client } = useNuxtApp()
const { data: hello } = await $client.hello.useQuery({ text: "client" })
This code also results in an error:
const client = useNuxtApp().$client
const { data: hello } = await client.hello.useQuery({ text: "client" })
But this code runs perfectly fine with no errors, including in the devtools:
const { data: hello } = await useNuxtApp().$client.hello.useQuery({ text: "client" })
wtf...
Also, using a composable also works perfectly fine...
// composables/useGreeting.ts
export default async function useGreeting(name: string) {
const { $client } = useNuxtApp()
return await $client.hello.useQuery({ text: name })
}
// pages/index.ts
const { data:hello, refresh } = await useGreeting("client")
So... Yeah.. That makes no sense to me. If someone wants to explain how perfectly functionally identical code is behaving completely differently... That would improve my sanity.
@Moonlight63 did this happens inside components or pages? i had no time try if the same happens when we use it in page or in a component
@cannap This was in a page. I have not tried inside a component, but I would expect the result to be the same since pages are just components anyway. I'll give it a shot.
@cannap @Moonlight63 :wave: Did you ever find out what caused this behavior ?
After investigating a bit it seems it is this line in @trpc/client
, createTRPCClientProxy.ts
that breaks.
return (client as any)[procedureType](fullPath, ...args)
I built @trpc/client
locally and added this snippet bellow right before the return
statement, my application's code still worked and my DevTools didn't break 😅
if (!client[procedureType]) {
console.log(procedureType, client);
return;
}
return (client as any)[procedureType](fullPath, ...args)
My console.log
gave the following result:
It definitely seems like procedureType
cannot index client
in some cases (that I have not determined yet).
Hope this is of use to someone !
patch base on @nicolassutter solution:
diff --git a/src/createTRPCClientProxy.ts b/src/createTRPCClientProxy.ts
index a4586de4f436e49724fd1b15aefe0a843e7e79cf..23166e54ed661165db34d3231facdbf0fe92e460 100644
--- a/src/createTRPCClientProxy.ts
+++ b/src/createTRPCClientProxy.ts
@@ -122,6 +122,10 @@ export function createTRPCClientProxy<TRouter extends AnyRouter>(
const fullPath = pathCopy.join('.');
+ if (!client[procedureType]) {
+ return;
+ }
+
return (client as any)[procedureType](fullPath, ...args);
});
});
but it seems to have stopped working
I was able to create a slightly ugly, but easy work around this based on what @Moonlight63 said. You can create a composable that returns the $client object inside a function and it'll work. I wonder whether this method would create a memory leak or something though - maybe could pair it with vueuse sharedComposable?
// ./composables/useTrpc.ts
export default () => {
const { $apiClient } = useNuxtApp();
return () => $apiClient;
};
You can use it like so:
// mycomponent.vue
<script setup lang="ts">
import useTrpc from "~/composables/useTrpc";
const tprc = useTprc();
const updateUser = async (id,name) =>{
await tprc().user.updateUser.mutate({
id,
name
});
}
</script>
...
When using
i have this in a component
the error is throwing but when i submit something it just works backend.js:749 TypeError: client[procedureType] is not a function i also had trycatch and so around same behavior
when i remove the code above it works The Component where i use it https://github.com/cannap/recipes/blob/main/components/common/CommonRecipeWidget.vue
Trpc: https://github.com/cannap/recipes/blob/main/plugins/0.trpc.ts
thanks